我有以下课程:
class FunctionCallback
{
public:
static CallbackHandle Create(const std::function<void(void)> &function);
template<typename T,typename... TARGS>
static CallbackHandle Create(const std::function<T(TARGS...)> &function);
};
然后我打电话给#39;创建&#39;像这样:
FunctionCallback::Create<void,float>([](float f) -> void {}); // Whether I use a lambda-function or a function pointer makes no difference
尽管这应该是正确的(?),但是visual studio强调读取行与消息:
Error: no instance of overloaded function "FunctionCallback::Create" matches the argument list
argument types are: (lambda []void (float f)->void)
然而,Visual Studio中的程序编译很好,没有任何警告或错误。 g ++ - 5无法用类似的消息完全编译它。
将其更改为:
FunctionCallback::Create<void,float>(std::function<void(float)>([](float f) -> void {}));
它不再显示消息,并在Windows和Linux上编译。
为什么不能正确推断出类型,除非我明确指出它?
答案 0 :(得分:0)
你几乎从不想推断出类型橡皮擦的类型,std::function
就是一个例子。除了少数例外,模板类型推导试图推断出参数的确切类型。对于std::function<T>
- 类型参数,这意味着如果相应的参数也是T
,编译器可以推导出std::function
。 lambda表达式的类型不是std::function
。
即使您明确指定了类型模板参数,在相应的类型被参数替换后,推论仍会继续。对于参数包,编译器仍会尝试推导其余参数,因此对于FunctionCallback::Create<void,float>
,编译器最终会得到:
template <typename... TARGS>
static CallbackHandle Create(std::function<void(float, TARGS...)> function);
并且除了std::function<void(float, TARGS...)>
之外,其他任何东西都不匹配(或者是从这种类型派生的东西);否则TARGS
的扣除失败。
如果您的目标是始终明确指定参数包的类型,则可以将该包(或整个参数)放在非推导的上下文中:
template <typename T> struct identity { using type = T; };
template <typename T> using identity_t = typename identity<T>::type;
struct FunctionCallback
{
template <typename T, typename... TARGS>
static void Create(identity_t<std::function<T(TARGS...)>> function);
};
FunctionCallback::Create<void, float>([](float f) -> void {});
但是,在这种情况下,您必须付出类型擦除的代价。相反,您可以考虑接受任何函数对象类型:,让编译器推导出参数的确切类型:
struct FunctionCallback
{
template <typename F>
static void Create(F function){}
};
FunctionCallback::Create([](float f) -> void {});