ODR使用行为的基本原理

时间:2016-05-16 19:42:27

标签: c++ language-lawyer constexpr

为什么通过const引用传递参数总是意味着对象是ODR使用的?我理解,因为标准以这种方式定义它,但为什么它至少对于积分常数没有异常?

例如(我几个小时前回答的例子):

struct T {
    static constexpr int i = 42;
};

void check(const int& z);

int main() {
    check(T::i); // <- 1
    check(42); // <- 2
}

(1)将在链接时分解错误 - 标准认为它是T::i的ODR使用,并且看不到定义。但是,标准对示例(2)没有问题。由于(2)必须有效,为什么(1)无法为整数constexpr工作?我意识到通常你需要获取对象的地址以通过引用传递它,但当然不是在数字文字的情况下。为什么标准不会为某些constexpr类型制作例外?

是否只是为了避免标准中有太多例外?但我认为允许使用如上所述非常有益!还有什么我看不到的吗?

2 个答案:

答案 0 :(得分:4)

  

但是,标准对例子(2)没有问题

因为在(2)的情况下,我们正在创建绑定到prvalue int const&的{​​{1}}类型的临时

但是42不是左值,它是左值 - 因此我们不会尝试创建临时值,我们会尝试绑定到实际的对象。但编译器如何知道T::i是一个你不想最终提供定义的左值,在这种情况下你真正的意思是构造一个临时的并复制它? T::i不是该类型的一部分,constexpr的类型只是i。您可能不得不跳过很多障碍,甚至尝试提出一个可以正确豁免int const但某些成员static constexpr int i的措辞。

一切都解决了什么问题?您可以通过const int i手动执行左值到右值的转换,并实现相同的目的。或者为+T::i提供定义。

ODR规则足够复杂 - 您需要一个令人信服的理由在其中钻一个洞。

答案 1 :(得分:2)

假设在两个TU中发生相同的呼叫。函数check可以取z的地址,标准保证它在两次调用中都会看到相同的地址。

除了分配单个存储位置并将i放在那里之外,您将如何实现这一目标?这几乎就是ODR所说的。