3

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.

max66
  • 65,235
  • 10
  • 71
  • 111
Yves
  • 11,597
  • 17
  • 83
  • 180
  • https://stackoverflow.com/questions/7741652/can-we-use-a-lambda-expression-as-the-default-value-for-a-function-argument – Cory Kramer Mar 29 '21 at 15:43
  • 2
    What version of C++ are you using? IIRC C++20 made this easier. – NathanOliver Mar 29 '21 at 15:45
  • If it's non-capturing, make the default a function pointer. Or leave the default out altogether. – sweenish Mar 29 '21 at 15:47
  • I'm not sure if this counts as a duplicate, but does [this](https://stackoverflow.com/questions/66726600/) answer your question? – cigien Mar 29 '21 at 15:51
  • @NathanOliver C++11 – Yves Mar 29 '21 at 15:51
  • @Yves Okay. I've added that to the question tags. – NathanOliver Mar 29 '21 at 15:52
  • In C++11 you can't have a lambda expression in an unevaluated context (like in the `decltype` specifier). This is possible in C++20 though! see https://stackoverflow.com/questions/5849059/lambda-expressions-as-class-template-parameters – GandhiGandhi Mar 29 '21 at 16:51
  • You can't default-construct a lambda prior to c++20, and then it's only possible with a non-capturing lambda. – super Mar 29 '21 at 16:57
  • 2
    Why do you want to pass the lambda as a template parameter, instead of just passing it as a function parameter? – super Mar 29 '21 at 16:58

2 Answers2

1

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;
}
GandhiGandhi
  • 1,029
  • 6
  • 10
1

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.

cigien
  • 57,834
  • 11
  • 73
  • 112
max66
  • 65,235
  • 10
  • 71
  • 111