19

I know it's like opening the Pandora box but it doesn't stop bothering me. Consider a simple example:

#include <type_traits>

template <auto>
struct Foo: std::false_type { };

template <>
struct Foo<[](){return 1;}()>:std::true_type { };

int main() {
    static_assert(Foo<1>::value);
}

I know lambdas cannot be declared inside unevaluated context, but obviously this is not the case here. What is even more weird clang 5.0.0 (which, I guess, first partially supports constexpr lambda) does compile it.

Is it a compiler bug or will C++17 allow this?

2 Answers 2

25

No, that is a compiler bug. gcc 7.1 correctly rejects the code.

[expr.prim.lambda]/2:

A lambda-expression is a prvalue whose result object is called the closure object. A lambda-expression shall not appear in an unevaluated operand, 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.

As you can see from the part that I marked as bold, a lambda expression cannot appear in a template argument list.

This is also made clear in a subsequent note:

[ Note: The intention is to prevent lambdas from appearing in a signature. — end note ]

If I were to guess, I would say that the bug comes about because starting with C++17, lambdas are implicitly constexpr, which makes them valid to be called in compile time expressions, like template arguments. But actually defining a lambda in a template argument is still illegal.


Note that this restriction has been lifted in C++20. :)

Sign up to request clarification or add additional context in comments.

10 Comments

yep I thought the standard committee intention was to present it, that's why I was surprised clang did compiler the code. I'll wait a bit and then accept your answer. Thanks!
@DanielJour No, sorry. But that would make meta programming even more confusing :)
@W.F. Jup, the paragraph I'm quoting is gone :) eel.is/c++draft/expr.prim.lambda#2
Nice finding! Thanks for sharing! Lets hope coders will use it reasonably ;)
Wait! Now lambda can be declared in decltype? :o
|
0

In C++17 you can pass pointer to lambda function as template parameter with function pointer type:

# include <cassert>

template<int(*fn)()>
int get_twice()
{
    return fn() * 2;
}

int main()
{
    int result = get_twice <+[]() { return 42; }> ();
    assert(result == 84);
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.