CWG Issue 1607 (original) (raw)
This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 117a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-04-13
1607. Lambdas in template parameters
Section: 7.5.6 [expr.prim.lambda]Status: C++14Submitter: Daniel KrüglerDate: 2013-01-19
[Moved to DR at the February, 2014 meeting.]
Lambda expressions cannot appear in unevaluated operands nor in evaluated portions of constant expressions. However, the following example appears to circumvent those restrictions:
template struct BoolSink { typedef void type; };
template <typename T, typename U> struct AddRvalueReferenceImpl { typedef T type; };
template struct AddRvalueReferenceImpl<T, typename BoolSink<false && [] { extern T &&tref; }>::type> { typedef T &&type; };
template struct AddRvalueReference : AddRvalueReferenceImpl<T, void> { };
namespace ImplHelpers { template typename AddRvalueReference::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() ...); }>::type, Args ...> { enum { value = 1 }; };
template <typename T, typename ...Args> struct IsConstructible : IsConstructibleImpl<T, void, Args ...> { };
struct DestroyMe { ~DestroyMe() = delete; };
static_assert(+IsConstructible::value, "error"); static_assert(!IsConstructible::value, "error"); static_assert(+IsConstructible<int [1]>::value, "error"); static_assert(!IsConstructible::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?
Additional notes, April, 2013:
Further discussion has arisen regarding _lambda-expression_s in function template signatures. Although the restriction that _lambda-expression_s cannot appear as unevaluated operands (7.5.6 [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-expression_s in template signatures, e.g.,
template void f(int [(0 && [] { for (auto x : T()) {} }, 1)]);
Four possible approaches for dealing with this issue have been suggested:
- Allow _lambda-expression_s in function template signatures. This would be costly in some implementations.
- 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-expression_s be mangled.
- 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.
- Do not allow _lambda-expression_s in function template signatures.
If any of these approaches were adopted, the rationale for disallowing _lambda-expression_s in unevaluated operands would be removed, so it might make sense to remove the restriction at the same time.
Proposed resolution (September, 2013):
Change 7.5.6 [expr.prim.lambda] paragraph 2 as follows:
...A lambda-expression shall not appear in an unevaluated operand (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 (22.10 [function.objects]). —_end note_]