c++ - 静态模板化 constexpr 嵌套类成员

标签 c++ templates c++14 language-lawyer constexpr

我有以下示例类 Foo嵌套类 Bar一切都是constexpr :

class Foo
{
private:
    template <typename T>
    struct Bar
    {
        constexpr Bar(){}
        constexpr int DoTheThing() const
        {
            return 1;
        }
    };
        
public:
    constexpr static auto b = Bar<int>{};
    constexpr Foo() {}
    constexpr int DoTheThing() const
    {
        return b.DoTheThing();
    }
};

我想测试调用 Foo::DoTheThing返回 1:

int main()
{
   constexpr Foo f;
   static_assert(f.DoTheThing() == 1, "DoTheThing() should return 1");
}

GCC 和 Clang 都在这里提示,但 MSVC 没有

GCC说:

error: constexpr Foo::Bar<T>::Bar() [with T = int] used before its definition

constexpr static auto b = Bar<int>{};

Clang :

error: constexpr variable b must be initialized by a constant expression

constexpr static auto b = Bar<int>{};

我不知道标准是否不允许这样做,但我的猜测是不知何故 b是一个不完整的类型。

让事情变得更有趣的是,如果我删除 constexpr,我可以让 GCC 和 Clang 正常运行。 ,或者如果我移动 Bar 的定义在Foo之外.

以下哪个编译器是正确的?

请注意,此问题的灵感来自于以下内容:

最佳答案

来自 n4140

§ 9.2.2 [class.mem](强调我的)

A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

Clang 和 GCC 是正确的。当您声明您的 static constexpr 成员时,该类不被认为是完整的,因此您无法构造它。这就是为什么将 Bar 的定义移出或删除 static constexpr 的原因(因为在定义非静态成员时它被认为是完整的)


澄清一下,特别是考虑这个问题:Static constexpr member of an inner class

我上面引用的标准基本上意味着除非另有说明一个类在其自身内被认为是不完整的*staticconstexprstatic constexpr 初始化器不属于 otherwise specified 部分,因此我们可以不使用类中声明的任何,其中包括嵌套类类型。

*表示您不能在类声明中使用它或它的成员。最著名的异常(exception)是在成员函数中。

关于c++ - 静态模板化 constexpr 嵌套类成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45841822/

相关文章:

c++ - 围绕 boost::ptree 头痛的模板化类

c++ - 带有模板参数的 Lambda 函数,而不是函数参数

c++ - 'default-initialization in copy-initialization context' 在 C++ 中是什么意思?

c++ - 游戏中的多态性

c++ - stringstream sgetn 在 iOS 5.1 上返回 NULL

c++ - 通用继承和重载运算符 +

c++ - 泛型函数的重载可以对其他重载开放吗?

c++ - 有没有办法为另一个进程设置 token ?

c++ - 在 64 位机器上,我可以安全地并行操作 64 位四字的各个字节吗?

c++ - 对 unique_ptrs 集的原始指针查找