【问题标题】:C++ static constexpr member redeclaration outside of class类外的 C++ 静态 constexpr 成员重新声明
【发布时间】:2014-02-25 22:02:38
【问题描述】:

对于下面的代码,为什么 main 中的第一种情况在没有重新声明 Foo::bar 的情况下可以正常工作,而函数的第二种情况需要它?

struct Foo{
static constexpr int bar = 30;
};
//Declaration of Foo::bar outside of struct
constexpr int Foo::bar;
int returnconstexpr(const int& x) { return x; }

int main()
{
    //Ok without declaration outside of struct
    std::cout << Foo::bar << std::endl;

    //Requires declaration outside of struct
    std::cout << returnconstexpr(Foo::bar) << std::endl;

    //Here static constexpr works as a definition
    static constexpr int x = 2;
    std::cout << returnconstexpr(x) << std::endl;

    return 0;
}

我假设这是因为在第一种情况下,编译器实际上只是保留了值,而在第二种情况下,函数需要一个在没有重新声明的情况下尚不存在的地址。如果是这样,那么我所说的是声明实际上是一个定义吗?我对此感到困惑,因为在类中提供了一个初始化程序,但它并没有使它成为一个定义。例如,第三种情况就可以了。

【问题讨论】:

    标签: c++ struct static definition constexpr


    【解决方案1】:

    我假设这是因为在第一种情况下,编译器 字面上只是坚持价值,而在第二种情况下 函数需要一个地址,如果没有 重新声明。如果是这样,那么我要说的是 声明实际上是一个定义?

    您已经回答了这个问题。静态成员在类之外定义,所以你有一个定义。当您将其传递给函数时,地址是必需的,因此您需要定义静态成员。在您的第一种情况下,编译器只需将 Foo::bar 替换为值。

    现在将函数签名更改为:

    int returnconstexpr(int x) { return x; }
    

    在上述情况下,您将不再需要定义。

    C++ 标准 3.2 中对此有规定:

    变量 x,其名称显示为潜在求值表达式 ex 是 odr-used 除非 x 是满足要求的对象 for 出现在常量表达式 (5.19) 中并且 ex 是 表达式 e 的一组潜在结果,其中 左值到右值转换 (4.1) 应用于 e,或者 e 是 丢弃值表达式(第 5 条)。

    在上述情况下,立即应用左值到右值的转换,因此它不是 odr-used(如标准所说),并且不需要定义。简单来说,这意味着它可以只使用值而不需要知道地址,但是当您使用引用类型(const int&)时,这需要编译器知道对象在内存中的位置。

    【讨论】:

    • 对,这是有道理的,否则每次包含标题时,它都会提供新的定义。谢谢。
    • @JamesLens:是的,为了防止 C++ 强制你在类之外定义静态成员。
    猜你喜欢
    • 1970-01-01
    • 2018-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    相关资源
    最近更新 更多