template-template-parameter deducation模板方法失败(虽然明确专用)
我正在尝试编写一个可以通过C++扩展的小脚本解释器。为此,函数处理程序被插入到一个调度表中。 要simplyfy我的问题,handlertype定义如下(在真正的代码,这包含了参数列表参数和返回类型):template-template-parameter deducation模板方法失败(虽然明确专用)
// Handler type using function_type = void(int);
调度表,就目前而言,是一个简单的无序地图用一种(类型)损坏的名称作为实施超载的关键:
// Dispatch table std::unordered_map<std::string, function_type*> fn_handlers;
方法被添加到这个表中直接,例如像一个简单的方法,该方法int
类型的两个参数(operator+ii
是manged名称这在我的情况下):
fn_handlers["operator+ii"] = my_add_handler;
然而,许多处理,特别是那些涉及到基本的数学,也接受各种参数, int
和double
的所有组合将是有效的,产生4个方法和4个调度表条目。因此我决定使用模板来实现这些方法。 举个例子,这可能是基本上是这样的(再次simplyfied):
template<class A, class B> void my_add_handler(int /* simplified... */)
{
// Something here A and B are needed
}
发送表,然后充满这样的:
fn_handlers["operator+ii"] = my_add_handler<int,int>; fn_handlers["operator+di"] = my_add_handler<double,int>;
fn_handlers["operator+id"] = my_add_handler<int,double>;
fn_handlers["operator+dd"] = my_add_handler<double,double>;
还有很多类型,但是这是正常的现在。无论如何,因为明明有模板参数和方法签名(重整名称)之间的相关性,我试图自动化这一点,你可以写(参数名mangeling将内部handler_provider做::补充):
handler_provider<int, int>::add<my_add_handler>("operator+"); handler_provider<double, int>::add<fn_add_handler>("operator+");
handler_provider<int, double>::add<fn_add_handler>("operator+");
handler_provider<double, double>::add<fn_add_handler>("operator+");
然后,它将在开始时采用参数,并将它们作为第二种类型的模板参数(这样就不必输入<int, int>
零件两次)。
只是为了澄清;我知道我的会明确专门的my_add_handler
模板是这样的:
handler_provider<int, int>::add<my_add_handler<int,int>>("test");
但正是这样的重复,我想省略(twict的<int,int>
)。
但是,我不断收到最后一部分的错误。该handler_provider::add
方法定义如下(参数名称mangeling上述被排除在外,因为它不是点这里按预期工作):
template<class... Ts> struct handler_provider
{
// Overload for templates, such as 'test_handler'
template<template<class...> class F>
static void add(const std::string name)
{
handler_provider<Ts...>::add<F<Ts...>>(name);
}
// Overload for non-template (or already specialized) handlers (aka. function pointers)
template<function_type F>
static void add(const std::string name)
{
fn_handlers[name] = F;
}
};
第一个重载,如说,应该对确切在上面描述的情况下,下面的处理程序安装了非模板函数和那些完全专用的函数。
但是,这给了我一个错误,告诉是从上面显示的调用的内部模板不能推断。我没有想到,我告诉编译器来推断所有东西,我完成了呼叫(再次)专业模板参数:
handler_provider<int, int>::add<my_add_handler>("operator+");
的论据外可变参数模板class... Ts
被明确命名<int, int>
和简单内部模板模板的参数命名为my_add_handler
。但是,编译器似乎忽略了这个(?)。这是输出我得到(GCC 5.4.0使用-std=c++14
):
$ g++ -std=c++14 sci_e1.cpp -o sci sci_e1.cpp: In function ‘int main()’:
sci_e1.cpp:45:55: error: no matching function for call to ‘handler_provider<int, int>::add(const char [5])’
handler_provider<int, int>::add<my_add_handler>("operator+");
^
sci_e1.cpp:17:15: note: candidate: template<template<class ...> class typedef F F> static void handler_provider<Ts>::add(std::__cxx11::string) [with F = F; Ts = {int, int}]
static void add(const std::string name)
^
sci_e1.cpp:17:15: note: template argument deduction/substitution failed:
sci_e1.cpp:24:15: note: candidate: template<void (* F)(int)> static void handler_provider<Ts>::add(std::__cxx11::string) [with void (* F)(int) = F; Ts = {int, int}]
static void add(const std::string name)
^
sci_e1.cpp:24:15: note: template argument deduction/substitution failed:
sci_e1.cpp:45:55: error: could not convert template argument ‘my_add_handler’ to ‘void (*)(int)’
handler_provider<int, int>::add<my_add_handler>("operator+");
^
我得到的第二个错误,那是完全地好,不应该是一个问题,因为这个过载应被踢出重载的模板类型。第一个错误是让我发疯的那个错误。
锵(3.9.0)是一个小更精确:
$ clang++ -std=c++14 sci_e1.cpp -o sci sci_e1.cpp:45:3: error: no matching function for call to 'add'
handler_provider<int, int>::add<my_add_handler>("test");
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sci_e1.cpp:17:15: note: candidate template ignored: invalid explicitly-specified argument for
template parameter 'F'
static void add(const std::string name)
^
sci_e1.cpp:24:15: note: candidate template ignored: invalid explicitly-specified argument for
template parameter 'F'
static void add(const std::string name)
^
1 error generated.
但我还是不明白的地方,我错在这里。我错过了什么?
感谢,
塞巴斯蒂安
为了更好的测试,这里是一个完整的例子:
#include <unordered_map> #include <string>
#include <iostream>
// Handler type
using function_type = void(int);
// Dispatch table
std::unordered_map<std::string, function_type*> fn_handlers;
// Handler provider (to install new handlers)
template<class... Ts>
struct handler_provider
{
// Overload for templates, such as 'test_handler'
template<template<class...> class F>
static void add(const std::string name)
{
handler_provider<Ts...>::add<F<Ts...>>(name);
}
// Overload for non-template (or already specialized) handlers (aka. function pointers)
template<function_type F>
static void add(const std::string name)
{
fn_handlers[name] = F;
}
};
template<class A, class B>
void test_handler(int v)
{
// Something here A and B are needed
}
void other_handler(int v)
{
// A handler without specialization
}
int main()
{
// Install handlers
handler_provider<int, int>::add<test_handler>("testii");
handler_provider<double, int>::add<test_handler>("testdi");
handler_provider<bool, bool, int>::add<other_handler>("otherbbi");
// Dispatch
fn_handlers["testii"](5); // Sould call test_handler<int, int>
fn_handlers["testdi"](5); // Should call test_handler<double, int>
fn_handlers["otherbbi"](5); // Should call other_handler
}
回答:
的问题是:根据标准,[temp.arg .template]/1,
[a] template - 模板模板参数的参数应该是类模板的名称或模板的别名,用id表达式表示。
因此,你不能实例化模板
template<template<class...> class F> static void add(const std::string name) {
handler_provider<Ts...>::add<F<Ts...>>(name);
}
与函数模板test_handler
。
为了解决这个问题,你必须做出一个test_handler
仿函数模板代替,即其更改为
template<class A, class B> struct test_handler {
void operator()(int v) {
// Something here A and B are needed
std::cout << __PRETTY_FUNCTION__ << " called with v = " << v << std::endl;
}
};
不幸的是,现在这是没有void(*)(int)
型较长,所以你不能把它插入到unordered_map
。因此,你必须在地图中的元素更改为std::function<function_type>
和调整add
重载模板函子来
// Overload for templates, such as 'test_handler' template<template<class...> class F>
static void add(const std::string name) {
fn_handlers[name] = F<Ts...>{};
}
完整的代码现在看起来是这样的:
#include <iostream> #include <functional>
#include <string>
#include <unordered_map>
// Handler typ
using function_type = void(int);
// Dispatch table
std::unordered_map<std::string, std::function<function_type>> fn_handlers;
// Handler provider (to install new handlers)
template<class... Ts>
struct handler_provider {
// Overload for templates, such as 'test_handler'
template<template<class...> class F>
static void add(const std::string name) {
fn_handlers[name] = F<Ts...>{};
}
// Overload for non-template (or already specialized) handlers (aka. function pointers)
template<function_type F>
static void add(const std::string name) {
fn_handlers[name] = F;
}
};
template<class A, class B>
struct test_handler {
void operator()(int v) {
// Something here A and B are needed
std::cout << __PRETTY_FUNCTION__ << " called with v = " << v << std::endl;
}
};
void other_handler(int v) {
// A handler without specialization
std::cout << __PRETTY_FUNCTION__ << " called with v = " << v << std::endl;
}
int main() {
// Install handlers
handler_provider<int, int>::add<test_handler>("testii");
handler_provider<double, int>::add<test_handler>("testdi");
handler_provider<bool, bool, int>::add<other_handler>("otherbbi");
// Dispatch
fn_handlers["testii"](5); // Sould call test_handler<int, int>
fn_handlers["testdi"](5); // Should call test_handler<double, int>
fn_handlers["otherbbi"](5); // Should call other_handler
}
这不正是你想要的,如可在此coliru中看到的那样。
如果你不想使用std::function
由于开销(在我的平台上std::function
使用32字节而不是8个字节作为指针),你也可以为处理程序编写自己的类型擦除结构。
以上是 template-template-parameter deducation模板方法失败(虽然明确专用) 的全部内容, 来源链接: utcz.com/qa/259072.html