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; 

然而,许多处理,特别是那些涉及到基本的数学,也接受各种参数, intdouble的所有组合将是有效的,产生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

回到顶部