std::function 的模板替换失败

Posted

技术标签:

【中文标题】std::function 的模板替换失败【英文标题】:Template substitution failure with std::function 【发布时间】:2015-10-13 09:34:11 【问题描述】:

我正在尝试将回调函数作为函数参数传递。但是在以下代码中出现模板替换失败错误。不确定模板替换失败的原因。

#include<iostream>
#include <map>
#include <tuple>
#include <functional>

template<typename A,typename B>
void myfun(std::map<A,B> & mm, std::function<std::tuple<A,B>(void)> fn)

    A key;
    B val;
    std::tie(key,val) = fn();
    mm[key] = val;


std::tuple<std::string,int> fun()

    return std::make_tuple(std::string("hi"),1);


int main()

    std::map<std::string,int> gg;
#if 0
        //fixed version
        std::function<std::tuple<std::string,int>(void)> yy = fun;//fixed
        myfun(gg,yy);//fixed
#else
        // error causing code
        myfun(gg,fun);
#endif

错误如下

main.cpp:8:6: note:   template argument deduction/substitution failed:

main.cpp:25:17: note:   mismatched types 'std::function<std::tuple<_T1, _T2>()>' and 'std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> (*)()'

     myfun(gg,fun);

【问题讨论】:

"hi"可能会被推导出为const char*,尝试使用std::string("hi") std::function 和普通函数是不同的东西,见***.com/questions/9054774/…。 @JohannesWalcher 或者更好的 "hi"s 使用 C++14 【参考方案1】:

编译器不能同时转换为std::function 并推断模板参数。它不理解任意函数指针和std::function 之间的映射。

有几种方法可以解决这个问题。

您可以在调用站点显式创建std::function

 myfun(gg,std::function<std::tuple<std::string,int>(void)>fun);`

您可以编写一个make_function 函数来为您推断类型。你可以在网上找到这方面的讨论和实现,例如here、here和here。

myfun(gg,make_function(fun));

您可以忘记std::function 并推断出整个函数类型。这是我将采取的方法:

template<typename A,typename B, typename Fun>
void myfun(std::map<A,B> & mm, Fun fn)

    A key;
    B val;
    std::tie(key,val) = fn();
    mm[key] = val;

【讨论】:

当你说编译器不能同时进行转换和演绎时,你是说它违反规则还是只是编译器不够聪明,无法做到这一点?

以上是关于std::function 的模板替换失败的主要内容,如果未能解决你的问题,请参考以下文章

模板函数替换仅在一个参数中未使用std :: function时才起作用

替换(或重新实现?)std::function 进行一些统计和测试

std::function 作为模板参数

Lambda 函数调用函数模板参数的静态函数失败

从std :: function中推导返回和参数类型作为模板函数参数传递?

std::function与std::bind