This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-11-11
[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 <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?
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.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-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:
Allow lambda-expressions 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-expressions 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-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.
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]