Lambdas in template parameters
7.5.5 [expr.prim.lambda]
Daniel Krügler

Created on 2013-01-19.00:00:00 last changed 81 months ago


Date: 2014-02-15.00:00:00

[Moved to DR at the February, 2014 meeting.]

Date: 2013-09-15.00:00:00

Proposed resolution (September, 2013):

Change 7.5.5 [expr.prim.lambda] paragraph 2 as follows:

...A lambda-expression shall not appear in an unevaluated operand (Clause Clause 7 [expr]), in a template-argument, in an alias-declaration, in a typedef declaration, or in the declaration of a function or function template outside its function body and default arguments. [Note: The intention is to prevent lambdas from appearing in a signature —end note]. [Note: A closure object behaves like a function object (20.14 [function.objects]). —end note]
Date: 2013-05-03.00:00:00

Additional notes, April, 2013:

Further discussion has arisen regarding lambda-expressions in function template signatures. Although the restriction that lambda-expressions cannot appear as unevaluated operands (7.5.5 [expr.prim.lambda] paragraph 2) was intended to avert the need to deal with them in function template signatures, the fact that 7.7 [expr.const] treats unevaluated subexpressions separately from unevaluated operands opens another avenue for lambda-expressions in template signatures, e.g.,

  template<typename T>
  void f(int [(0 && [] { for (auto x : T()) {} }, 1)]);

Four possible approaches for dealing with this issue have been suggested:

  1. Allow lambda-expressions in function template signatures. This would be costly in some implementations.

  2. Give a function template internal linkage if its signature includes a lambda-expression. This would allow SFINAE and redeclaration to work without requiring that lambda-expressions be mangled.

  3. Specify that a function signature containing a lambda-expression is not a redeclaration of any other function template, which would allow SFINAE to work but not require declaration matching and mangling.

  4. Do not allow lambda-expressions in function template signatures.

If any of these approaches were adopted, the rationale for disallowing lambda-expressions in unevaluated operands would be removed, so it might make sense to remove the restriction at the same time.

Date: 2013-10-14.00:00:00
N3690 comment CA 3

Lambda expressions cannot appear in unevaluated operands nor in evaluated portions of constant expressions. However, the following example appears to circumvent those restrictions:

  template <bool> struct BoolSink { typedef void type; };

  template <typename T, typename U>
  struct AddRvalueReferenceImpl { typedef T type; };

  template <typename T>
  struct AddRvalueReferenceImpl<T, typename BoolSink<false &&
     [] {
       extern T &&tref;
     }>::type> {
    typedef T &&type;

  template <typename T>
  struct AddRvalueReference : AddRvalueReferenceImpl<T, void> { };

  namespace ImplHelpers {
    template <typename T>
    typename AddRvalueReference<T>::type create(void) { }

  template <typename T, typename U, typename ...Args>
  struct IsConstructibleImpl { enum { value = 0 }; };

  template <typename T, typename ...Args>
  struct IsConstructibleImpl<T, typename BoolSink<false &&
     [] {
       T t( ::ImplHelpers::create<Args>() ...);
     }>::type, Args ...> {
    enum { value = 1 };

  template <typename T, typename ...Args>
  struct IsConstructible : IsConstructibleImpl<T, void, Args ...> { };

  struct DestroyMe {
    ~DestroyMe() = delete;

  static_assert(+IsConstructible<int>::value, "error");
  static_assert(!IsConstructible<void>::value, "error");
  static_assert(+IsConstructible<int [1]>::value, "error");
  static_assert(!IsConstructible<DestroyMe>::value, "error");
  static_assert(!IsConstructible<int *, char *>::value, "error");

  static_assert(+IsConstructible<int &&, int>::value, "error");
  static_assert(!IsConstructible<int &&, int &>::value, "error");
  static_assert(+IsConstructible<int &&, int &&>::value, "error");

Is this intended?

Date User Action Args
2014-11-24 00:00:00adminsetstatus: dr -> c++14
2014-03-03 00:00:00adminsetmessages: + msg4935
2014-03-03 00:00:00adminsetstatus: ready -> dr
2013-10-14 00:00:00adminsetmessages: + msg4572
2013-10-14 00:00:00adminsetstatus: drafting -> ready
2013-05-03 00:00:00adminsetmessages: + msg4329
2013-05-03 00:00:00adminsetstatus: open -> drafting
2013-01-19 00:00:00admincreate