C ++ lambda表达式作为函数模板中的参数

时间:2015-02-10 20:10:54

标签: c++ templates lambda

我需要定义一个函数,它将一个集合和一个函数作为输入来进行集合的漂亮打印。就此而言,我想明确指定函数的类型,以便编译器可以递归匹配,从而签名

template<typename T, PrettyPrinter>
std::string to_string(const std::set<T>& set, PrettyPrinter printer);

不够精确,因为编译器无法推断所需的函数对象的类型。所以相反,我想使用显式输入

template<typename T>
std::string PrettyPrinting::to_string(const std::set<T>& set, std::function<std::string(const T&)> printer){
    const char* separator = ", ";
    const char* leftDelimiter = "{";
    const char* rightDelimiter = "}" 

    std::string output = leftDelimiter;
    if(set.begin() == set.end()) return output + rightDelimiter;

    typename std::set<T>::const_iterator it = set.begin();
    output += printer(*it);
    for(++it; it != set.end(); it++) output.append(separator) += printer(*it);

    return output + rightDelimiter;
}

这符合我的期望。但是,我不能在另一个模板构造中使用lamba表达式

std::string to_string(const std::set<std::string>& set){
    return to_string(set, [](const std::string& input){ return input; });
}

我得到一些奇怪的错误,lambda函数不适合参数。另一方面,以下代码工作

inline std::string to_string(const std::set<std::string>& set){
   std::function<std::string(const std::string&)> printer = [](const std::string& input){ return input; };
   return to_string(set, printer);
}

有没有合理的理由为什么编译器需要一个显式的函数对象?我应该将什么指定为一个类型,以便我可以直接将lambda表达式写为函数参数?

1 个答案:

答案 0 :(得分:1)

Lambdas和std::function<...>是两种不同的类型。 Template argument deduction并不关心隐式转换。试试这个:

template<typename T, typename PrintLambda, typename = std::enable_if_t<std::is_convertible<PrintLambda, std::function<std::string(const T&)> >::value >>
std::string PrettyPrinting::to_string(const std::set<T>& set, PrintLambda printer);

以上内容通过检查PrintLambda是否可以转换为相应的std::function来确保{{1}}具有正确的签名。