是否未指定在未评估的上下文中实例化模板/lambda

Is it unspecified to instantiate template/lambda in unevaluated context?

本文关键字:实例化 lambda 上下文 未指定 评估 是否      更新时间:2023-10-16

我尝试以下代码检查模板是否在未评估的上下文中实例化:

#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 as lambda :(错误(

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

演示

lamdba的operator()实例化是否正常?

GCC/clang具有相同的行为。

lambda情况实际上与其他情况不同!您没有为lambda指定返回类型,因此可以推导它。为了扣除,必须实例化lambda。

函数对象不是这种情况,因为您指定返回类型为 void。更改Lambda以返回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(),以推断出返回类型。