Не определено ли создавать экземпляр шаблона / лямбды в неоцененном контексте? - PullRequest
13 голосов
/ 05 июля 2019

Я пытаюсь использовать следующий код, чтобы проверить, создан ли шаблон в неоцененном контексте:

#include "foo.h"

template <typename T = int>
constexpr auto f(int)
// from declaration, foo(std::declval<T>()) is allowed.
// Even if definition would produce errors if instantiated
-> decltype(foo(std::declval<T>()), void(), 42)
{
    return 42;
}
static_assert(f(0) == 42);

с foo в качестве функции шаблона: (без ошибок)

template <typename ...Ts>
void foo(Ts... args)
{
    static_assert(sizeof...(Ts) == 42, "!");
    ((args += ""), ...);
}

Демо

с foo в качестве обычного функтора: (без ошибок)

struct Foo
{
    template <typename ...Ts>
    void operator ()(Ts... args) const
    {
        static_assert(sizeof...(args) == 42, "!");
        ((args += ""), ...);
    }
} foo;

Демо

Но foo как лямбда: (Ошибка)

auto foo = [](auto... args)
{
    static_assert(sizeof...(args) == 42, "!"); // Triggers
    ((args += ""), ...);                       // spotted as invalid: int += const char*
};

Демо

Это нормально, что создается экземпляр operator() lamdba?

gcc / clang ведут себя так же.

1 Ответ

15 голосов
/ 05 июля 2019

Лямбда-корпус на самом деле отличается от других! Вы не указываете тип возврата для лямбды, поэтому он выводится. Для того, чтобы произошел вывод, должна быть создана лямбда.

Это не относится к объекту функции, так как там вы указали тип возвращаемого значения void. Изменение лямбды на возвращение void, чтобы избежать удержания, делает счастливым gcc / clang. :)

auto foo = [](auto... args) -> void // <---
{
    static_assert(sizeof...(args) == 42, "!");
    ((args += ""), ...);
};

И если вы измените объект функции следующим образом:

struct Foo
{
    template <typename ...Ts>
    auto operator ()(Ts... args) const // <---- placeholder as return type
    {
        static_assert(sizeof...(args) == 42, "!");
        ((args += ""), ...);
    }
} foo;

он также создает экземпляр Foo::operator(), чтобы иметь возможность определить тип возвращаемого значения.

...