对于以下代码,为什么 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;
}
我假设这是因为在第一种情况下,编译器实际上只是保留该值,而在第二种情况下,该函数需要一个在没有重新声明的情况下尚不存在的地址。如果是这样,那么我所说的声明实际上是定义吗?我对此感到困惑,因为类中提供了初始化程序,但它并没有使其成为定义。例如,第三种情况就可以正常工作。
我假设这是因为在第一种情况下,编译器
从字面上看,只是保留该值,而在第二种情况下
函数需要一个不存在的地址
重新声明。如果是这样的话,那么我要说的就是
声明实际上是一个定义?
你已经回答了问题。静态成员是defined在课堂之外,所以你所拥有的只是一个定义。当您将其传递给函数时,地址是必需的,因此您需要定义静态成员。在第一种情况下,编译器只是替换Foo::bar
与价值。
现在将函数签名更改为以下内容:
int returnconstexpr(int x) { return x; }
在上述情况下,您将不再需要该定义。
C++ 标准 3.2 中的规则如下:
名称显示为潜在计算表达式的变量 x
ex 是 odr-used 除非 x 是满足要求的对象
出现在常量表达式 (5.19) 中,并且 ex 是以下元素
表达式 e 的潜在结果集,其中
左值到右值转换 (4.1) 应用于 e,或者 e 是
丢弃值表达式(第 5 条)。
在上述情况下,立即应用左值到右值的转换,因此不使用 odr(如标准所述)并且不需要定义。简单来说,这意味着它可以只使用值而不需要知道地址,但是当您使用引用类型(const int&)时,这需要编译器知道对象在内存中的位置。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)