May a lambda expression be a default template argument?

2,101 views
Skip to first unread message

Vlad from Moscow

unread,
Oct 2, 2013, 7:46:32 PM10/2/13
to std-dis...@isocpp.org
Can someone point at where in the C++ Standard there is said that a lambda expression may not be a default template argument.
 
I tried to compile the following declaration  with using GCC and I got a compilation error
 
template <class T,
          class U = []( const T & ){ return ( true ); }>
 
void f( U u = U() );
 
 

Richard Smith

unread,
Oct 2, 2013, 7:56:53 PM10/2/13
to std-dis...@isocpp.org
A lambda-expression is an expression, not a type. Maybe you meant:

auto x = []( const T & ){ return ( true ); };
template <class T, class U = decltype(x)>
void f(U u = x);

Vlad from Moscow

unread,
Oct 2, 2013, 8:04:24 PM10/2/13
to std-dis...@isocpp.org
 
But I want that the lambda would depend on the first template parameter of the function.

четверг, 3 октября 2013 г., 3:56:53 UTC+4 пользователь Richard Smith написал:

Richard Smith

unread,
Oct 2, 2013, 8:14:28 PM10/2/13
to std-dis...@isocpp.org
On Wed, Oct 2, 2013 at 5:04 PM, Vlad from Moscow <vlad....@mail.ru> wrote: 
But I want that the lambda would depend on the first template parameter of the function.

In C++1y you have a number of options. You could use a generic lambda:

auto x = [](const auto&) { return true; }
template<typename T, typename U = decltype(x)> void f(U u = x);

or put the lambda inside a function:

template<typename T> auto get() { return [](const T&) { return true; }; }
template<typename T, typename U = decltype(get<T>())> void f(U u = get<T>());

or put it in a variable template:

template<typename T> auto x = [](const T&) { return true; };
template<typename T, typename U = decltype(x<T>)> void f(U u = x<T>);

In C++11, it's not so easy. In that case you could use an overload rather than a default argument:

template<typename T, typename U> void f(U u);
template<typename T> void f() { f([](const T&){ return true; }); }
 
четверг, 3 октября 2013 г., 3:56:53 UTC+4 пользователь Richard Smith написал:
On Wed, Oct 2, 2013 at 4:46 PM, Vlad from Moscow <vlad....@mail.ru> wrote:
Can someone point at where in the C++ Standard there is said that a lambda expression may not be a default template argument.
 
I tried to compile the following declaration  with using GCC and I got a compilation error
 
template <class T,
          class U = []( const T & ){ return ( true ); }>

A lambda-expression is an expression, not a type. Maybe you meant:

auto x = []( const T & ){ return ( true ); };
template <class T, class U = decltype(x)>
void f(U u = x);

--
 
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussio...@isocpp.org.
To post to this group, send email to std-dis...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-discussion/.

Róbert Dávid

unread,
Oct 3, 2013, 4:27:51 PM10/3/13
to std-dis...@isocpp.org
Problem with the workarounds posted, that they not necessary work everywhere: I'm thinking of inside a class definition: if you wanted your void f() function template to be a class member, you have to find another way to do this some another way (overloading or specialization).

Lambdas cannot appear in unevaluated contexts, that's why it doesn't compile, even if you put decltype around the lambda:
template <class T, class U = decltype([](const T&){return true;})>
void f(U u = U());
Also, the "=U()" part won't work as well, not even in C++14. I had the proposal for default constructor of closures a while back, but didn't pursue it because of this unevaluated context part. What is a shame, the new generic captures and polymorphic arguments make lambdas an insanely powerful tool to define functors, would be awesome if we could use them as template arguments.

Regards, Robert

Richard Smith

unread,
Oct 3, 2013, 4:36:27 PM10/3/13
to std-dis...@isocpp.org
On Thu, Oct 3, 2013 at 1:27 PM, Róbert Dávid <lrd...@gmail.com> wrote:


2013. október 3., csütörtök 1:46:32 UTC+2 időpontban Vlad from Moscow a következőt írta:
Can someone point at where in the C++ Standard there is said that a lambda expression may not be a default template argument.
 
I tried to compile the following declaration  with using GCC and I got a compilation error
 
template <class T,
          class U = []( const T & ){ return ( true ); }>
 
void f( U u = U() );
 
 
Problem with the workarounds posted, that they not necessary work everywhere: I'm thinking of inside a class definition: if you wanted your void f() function template to be a class member, you have to find another way to do this some another way (overloading or specialization).

Both a generic lambda and a static data member template still work in that context.
 
Lambdas cannot appear in unevaluated contexts, that's why it doesn't compile, even if you put decltype around the lambda:
template <class T, class U = decltype([](const T&){return true;})>
void f(U u = U());
Also, the "=U()" part won't work as well, not even in C++14. I had the proposal for default constructor of closures a while back, but didn't pursue it because of this unevaluated context part. What is a shame, the new generic captures and polymorphic arguments make lambdas an insanely powerful tool to define functors, would be awesome if we could use them as template arguments.

Regards, Robert

--

Róbert Dávid

unread,
Oct 3, 2013, 4:56:05 PM10/3/13
to std-dis...@isocpp.org


2013. október 3., csütörtök 22:36:27 UTC+2 időpontban Richard Smith a következőt írta:
On Thu, Oct 3, 2013 at 1:27 PM, Róbert Dávid <lrd...@gmail.com> wrote:


2013. október 3., csütörtök 1:46:32 UTC+2 időpontban Vlad from Moscow a következőt írta:
Can someone point at where in the C++ Standard there is said that a lambda expression may not be a default template argument.
 
I tried to compile the following declaration  with using GCC and I got a compilation error
 
template <class T,
          class U = []( const T & ){ return ( true ); }>
 
void f( U u = U() );
 
 
Problem with the workarounds posted, that they not necessary work everywhere: I'm thinking of inside a class definition: if you wanted your void f() function template to be a class member, you have to find another way to do this some another way (overloading or specialization).

Both a generic lambda and a static data member template still work in that context.

How exactly? I have failed to have it compiled: http://ideone.com/WDVc9f
 

Richard Smith

unread,
Oct 3, 2013, 5:35:33 PM10/3/13
to std-dis...@isocpp.org
On Thu, Oct 3, 2013 at 1:56 PM, Róbert Dávid <lrd...@gmail.com> wrote:


2013. október 3., csütörtök 22:36:27 UTC+2 időpontban Richard Smith a következőt írta:
On Thu, Oct 3, 2013 at 1:27 PM, Róbert Dávid <lrd...@gmail.com> wrote:


2013. október 3., csütörtök 1:46:32 UTC+2 időpontban Vlad from Moscow a következőt írta:
Can someone point at where in the C++ Standard there is said that a lambda expression may not be a default template argument.
 
I tried to compile the following declaration  with using GCC and I got a compilation error
 
template <class T,
          class U = []( const T & ){ return ( true ); }>
 
void f( U u = U() );
 
 
Problem with the workarounds posted, that they not necessary work everywhere: I'm thinking of inside a class definition: if you wanted your void f() function template to be a class member, you have to find another way to do this some another way (overloading or specialization).

Both a generic lambda and a static data member template still work in that context.

How exactly? I have failed to have it compiled: http://ideone.com/WDVc9f

(Your compilation failure doesn't indicate the problem, because GCC seems to allow lambda-expressions in constant expressions.)

Here's one way that works in clang's c++1y mode:

#include <iostream>

template<typename T> auto default_lambda() {
  return [](const T&) { return 42; };
}

template<typename T>
struct A {
  template<class U = decltype(default_lambda<T>())>
  void func(U u = default_lambda<T>()) { std::cout << u(T{}); }
};

int main() {
  A<int> f;
  f.func();
}

(Various other options, putting the lambda inside A, should also work, but cause Clang trunk to crash right now.)

Róbert Dávid

unread,
Oct 3, 2013, 6:07:02 PM10/3/13
to std-dis...@isocpp.org

So, there is no compiler that can do that yet :)

The thing is, with lambdas that all code is inline. It makes it infinitely less useful if you need to wrap it and move it 10 lines earlier - there is no need to wrap everything in lambdas, use a good old functor class when you don't need or can't use the direct benefit of inline code, and the solution is free of any arcane nuisances lambdas have.

Regards, Robert
Reply all
Reply to author
Forward
0 new messages