为什么有状态但“constexpr” lambda 不能用作非类型模板参数?

kla*_*ndl 5 c++ lambda constexpr c++20 non-type-template-parameter

不知何故,我仍然认为 lambda 是常规函数对象的“语法糖”,因此令我惊讶的是,在 C++-20 下,有状态但在其他方面的constexprlambda 实例不能用作非类型模板参数,这与等效的函数对象实例不同。

谁能解释这种行为或决定?

Godbolt示例:

struct always_fn {
    const int x;

    int operator()() const
    {
        return x;
    }
};
inline constexpr always_fn always_f{5};

// lambda equivalent to `always_f`
inline constexpr auto always_2_f = [x = 5]() {
    return x;
};

template<typename F>
struct wrapped {
    F f_;
};
inline constexpr auto wrapped_f = wrapped{always_f};
inline constexpr auto wrapped_2_f = wrapped{always_2_f};

template<auto f>
void pass() {}

int main() {
    pass<always_f>();
    pass<wrapped_f>();
    // error: no matching function for call to 'pass'
    pass<always_2_f>();
 // ^~~~~~~~~~~~~~~~
    // error: no matching function for call to 'pass'
    pass<wrapped_2_f>();
 // ^~~~~~~~~~~~~~~~~

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

use*_*522 6

Lambda(无论是否有状态)永远不是结构类型,因此永远不能用作非类型模板参数。

CWG 2542澄清了这一点,但编译器可能尚未实现。

如果不做出这样的决定,lambda 是否具有结构类型将取决于实现细节,例如闭包类型的成员是私有还是公共,或者必须更详细地指定闭包类型的实现。

特别是,没有任何要求x在等效函数对象中应该是公共的,如果不是,那么它也不能用作非类型模板参数。