【问题标题】:"template argument deduction/substitution failed" error with function object with parameter pack带有参数包的函数对象出现“模板参数推导/替换失败”错误
【发布时间】:2019-05-05 13:21:20
【问题描述】:

我正在尝试创建一个函数,该函数接受可变数量的任何类型的参数,但即使是我所做的简单示例也会出错

#include <iostream>
#include <functional>

template<class... Ts>
void callFunction(const std::function<void(Ts...)>& function, Ts... parameters)
{
    function(parameters...);
}

void myFunc(const std::string& output)
{
    std::cout << output << std::endl;
}

int main() 
{
    callFunction<const std::string&>(&myFunc, "Hello world");
    return 0;
}

当我在Ideone 中运行上面的代码时,我得到了这个错误:

prog.cpp: In function ‘int main()’:
prog.cpp:17:57: error: no matching function for call to ‘callFunction(void (*)(const string&), const char [12])’
  callFunction<const std::string&>(&myFunc, "Hello world");
                                                         ^
prog.cpp:5:6: note: candidate: template<class ... Ts> void callFunction(const std::function<void(Ts ...)>&, Ts ...)
 void callFunction(const std::function<void(Ts...)>& function, Ts... parameters)
      ^~~~~~~~~~~~
prog.cpp:5:6: note:   template argument deduction/substitution failed:
prog.cpp:17:57: note:   mismatched types ‘const std::function<void(Ts ...)>’ and ‘void (*)(const string&) {aka void (*)(const std::__cxx11::basic_string<char>&)}’
  callFunction<const std::string&>(&myFunc, "Hello world");

【问题讨论】:

    标签: c++ templates variadic-templates std-function template-argument-deduction


    【解决方案1】:

    一个简单的建议:将可调用对象作为推断的类型名接收,而不是作为std::function

    我的意思是(添加完美转发)

    template <typename F, typename ... Ts>
    void callFunction(F const & func, Ts && ... pars)
     { func(std::forward<Ts>(pars)...); }
    

    而且,显然,不用解释就直接调用它

    callFunction(&myFunc, "Hello world");
    

    这是避免将可调用对象转换为std::function 的额外优势。

    无论如何,我在您的代码中发现了两个问题:

    1) 如果你接收到函数作为 std::function 接收参数类型列表(在这种情况下是可变参数列表,但对于这个问题并不重要)作为相同类型的参数列表,你有要确定两个列表中的类型完全匹配

    这不是您的情况,因为该函数接收到 std::string const &amp;,并且您将字符串文字 "Hello world" 作为参数传递,这是一个不同类型的 char const [12]

    当要推导类型时,会导致编译错误,因为编译器无法在这两种类型之间进行选择。

    你可以解决接收两个类型列表

    template <typename ... Ts1, typename Ts2>
    void callFunction (std::function<void(Ts1...)> const & function,
                       Ts2 && ... parameters)
     { function(std::forward<Ts2>(parameters)...); }
    

    但现在我们遇到了第二个问题

    2) 你传递一个指针函数 (&amp;myFunc),其中 callFunction() 等待 std::function

    我们遇到了鸡蛋问题,因为&amp;myFunc 可以转换为std::function,但不是std::function

    因此编译器无法从&amp;myFunc 推断出Ts... 类型列表,因为它不是std::function,也无法将&amp;myFunc 转换为std::function,因为不知道@987654341 @类型列表。

    我看到您已经解释了 Ts... 列表中的 first 类型,但这还不够,因为 Ts... 列表是可变参数,所以编译器不知道那里只是Ts... 列表中的一个类型。

    此问题的一个简单解决方案是将函数作为简单推导的F 类型传递。

    否则,如果您编写了带有两个模板类型列表的callFunction(),则可以将std::function 传递给函数

    std::function<void(std::string const &)>  f{&myFunc};
    
    callFunction(f, "Hello world");
    

    但我认为这不是一个令人满意的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-28
      • 2014-09-22
      • 1970-01-01
      • 1970-01-01
      • 2015-07-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多