Подтвердить что ты не робот

Смогу ли я объявить constexpr lambda внутри параметра шаблона?

Я знаю это как открытие коробки Пандоры, но это не мешает мне беспокоить меня. Рассмотрим простой пример:

#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);
}

Я знаю, что lambdas нельзя объявить в неоценимом контексте, но, очевидно, это не так. Что еще более странное clang 5.0.0 (которое, я думаю, сначала частично поддерживает constexpr lambda) компилирует его.

Является ли это ошибкой компилятора или разрешит ли это С++ 17?

4b9b3361

Ответ 1

Нет, это ошибка компилятора. gcc 7.1 правильно отклоняет код.

[expr.prim.lambda]/2:

Лямбда-выражение - это prvalue, результат результата которого называется замыкающим объектом. Лямбда-выражение не должно появляться в неопубликованном операнде в аргументе шаблона, в объявлении alias, в объявлении typedef или в объявлении шаблона функции или функции вне его тела функции и аргументы по умолчанию.

Как видно из части, выделенной мной полужирным шрифтом, выражение lambda не может появляться в списке аргументов шаблона.

Это также ясно из следующей заметки:

[Примечание. Цель состоит в том, чтобы предотвратить появление лямбда в подписи. - конечная нота]

Если бы я должен был догадаться, я бы сказал, что ошибка возникает, потому что, начиная с С++ 17, lambdas неявно constexpr, что делает их действительными для вызова в выражениях времени компиляции, таких как аргументы шаблона. Но фактически определение лямбда в аргументе шаблона по-прежнему является незаконным.


Обратите внимание, что это ограничение было снято в С++ 20.:)

Ответ 2

В С++ 17 вы можете передать указатель на лямбду в качестве параметра шаблона с типом указателя на функцию:

# include <cassert>

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

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