简体   繁体   中英

C++ lambda expression as an argument in function template

I need to define a function that takes a set and a function as input to do the pretty printing of sets. For that matter I would like to explicitly specify the type of the function so that the compiler could recursive matching and thus the signature

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

is not precise enough, as the compiler cannot infer the type of a function object needed. So instead, I would like to use explicit typing

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

This does what I expect. However, I cannot use lamba expression in another template construction

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

I get some weird error that lambda function is not appropriate argument. On the other hand, the following code works

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

Is there any rational reasons why does the compiler need an explicit function object? What should I specify as a type so that I could write lambda expressions directly as function arguments?

Lambdas and std::function<...> are two different types. Template argument deduction does not care about implicit conversions. Try this:

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

The above ensures that PrintLambda has the right signature by checking if it is convertible to the appropriate std::function .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM