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

Posted

技术标签:

【中文标题】是否未指定在未评估的上下文中实例化模板/lambda?【英文标题】:Is it unspecified to instantiate template/lambda in unevaluated context? 【发布时间】:2019-11-15 23:28:38 【问题描述】:

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

#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 += ""), ...);

Demo

foo 作为常规函子:(没有错误)

struct Foo

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

Demo

foo 为 lambda:(错误)

auto foo = [](auto... args)

    static_assert(sizeof...(args) == 42, "!"); // Triggers
    ((args += ""), ...);                       // spotted as invalid: int += const char*
;

Demo

lamdba的operator()被实例化正常吗?

gcc/clang 具有相同的行为。

【问题讨论】:

【参考方案1】:

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() 以便能够推断返回类型。

【讨论】:

以上是关于是否未指定在未评估的上下文中实例化模板/lambda?的主要内容,如果未能解决你的问题,请参考以下文章

在未提升的上下文中执行代码

如何阻止 EL 表达式在未呈现的 JSF 组件中进行评估?

为啥未使用的成员模板函数的类模板实例化失败

MSVC:隐式模板实例化,但未使用模板构造函数

如果未提供模型,则 ASP.NET MVC 自动模型实例化

是否可以通过 OBEX 在未配对的设备之间传输文件?