我需要定义一个函数,它将一个集合和一个函数作为输入来进行集合的漂亮打印。就此而言,我想明确指定函数的类型,以便编译器可以递归匹配,从而签名
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表达式写为函数参数?
答案 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}}具有正确的签名。