Yves
Yves

Reputation: 12431

How to pass a lambda to a template paramater

I'm trying to define a function func(), which returns a std::string.

template<typename T = std::string, template<typename> typename F = decltype([](const T &t){return t;})>
std::string func(const T &t){
    F f;
    return f(t);
}

As you see, what I'm trying to do is to pass a lambda as the template parameter so that I can call the function func() like this:

func<int, decltype([](int a){return std::to_string(a);})>(2);

Also, I set the values by default for the template parameters so that I can call it like this:

func<>("abc");

However, the code above gave me an error:

<source>:39:54: error: expected unqualified-id before 'decltype'
   39 | template<typename T, template<typename> typename F = decltype([](const T &t){return t;})>
      |                                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:39:54: error: invalid default argument for a template template parameter
<source>:39:54: error: expected '>' before 'decltype'

BTW, the version of my C++ is C++11.

Upvotes: 3

Views: 814

Answers (2)

max66
max66

Reputation: 66230

In C++11? With a lambda as template parameter?

Given that a lambda (before C++20) can't be used in an unevaluated context (so in a decltype()) and can't be default constructed, I don't see a way.

The best I can imagine, in C++11, to reproduce something similar is something as follows

template <typename T, typename F = std::function<std::string(T const &)>>
std::string func (T const & t, F f = [](const T &t){return std::string{t};})
 { return f(t); }

that you can call with only the first argument

func("abc");

given that you accept the default lambda (but is saved as a std::function).

You can also pass another lambda, if you don't like the default one

func(1, [](int const &){ return "one"; });

but as a traditional argument, not as template parameter.

Upvotes: 1

GandhiGandhi
GandhiGandhi

Reputation: 1350

In C++11 you can't have a lambda expression in an un-evaluated context, so you'd have to implement this differently I think.

C++20 added this feature, so here's a sample that will compile and run in C++20.

#include <iostream>
#include <string>


template<typename T = std::string, typename F = decltype([](const T &t)->std::string{return t;})>
std::string func(const T &t){
    F f;
    return f(t);
}



int main() {
    // convert int to string
    std::cout << func<int, decltype([](int a){return std::to_string(a);})>(2) << std::endl;
    // take float parameter, but just ignore the parameter
    std::cout << func<float, decltype([](float a){return "ignore the param";})>(2.2) << std::endl;
    // default lambda
    std::cout << func("abc") << std::endl;

    return 0;
}

Upvotes: 1

Related Questions