【问题标题】:Implicit template argument is invalid, but compiles anyway隐式模板参数无效,但仍可编译
【发布时间】:2015-12-12 17:40:30
【问题描述】:

我有以下课程:

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);
};

然后我像这样调用“创建”:

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 上都可以编译。

除非我明确指定,否则为什么不能正确推断类型?

【问题讨论】:

  • 尽管 vs.net 对错误的预测是对还是错。使用模板时不要在编译前依赖它的消息。

标签: c++ templates c++11 variadic-templates implicit-conversion


【解决方案1】:

您几乎从不想推断类型橡皮擦的类型,std::function 就是一个例子。除了少数例外,模板类型推导尝试推导参数的确切类型。对于std::function&lt;T&gt;-type 参数,这意味着如果相应的参数也是std::function,编译器也可以推断出T。 lambda 表达式的类型不是std::function

即使你显式地指定了类型模板参数,在相应的类型被参数替换后,推导仍然继续。在参数包的情况下,编译器仍会尝试推断其余参数,因此对于FunctionCallback::Create&lt;void,float&gt;,编译器最终会得到:

template <typename... TARGS>
static CallbackHandle Create(std::function<void(float, TARGS...)> function);

除了std::function&lt;void(float, TARGS...)&gt;(或从这种类型派生的东西)之外,这不会匹配任何其他东西;否则对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 {});

DEMO

但是,在这种情况下,您将不得不为类型擦除付出代价。相反,您可以考虑接受任何函数对象类型:,让编译器推断出参数的确切类型:

struct FunctionCallback
{
    template <typename F>
    static void Create(F function){}
};

FunctionCallback::Create([](float f) -> void {});

DEMO 2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-12
    • 1970-01-01
    • 1970-01-01
    • 2012-03-26
    • 2019-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多