ODR使用行为的基本原理
ODR-usage behaviour rationale
为什么通过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)没有问题
因为在(2)的情况下,我们正在创建一个类型为int const&
的临时,它绑定到prvalue 42
。
但是T::i
不是一个右值,它是一个左值——所以我们不会试图创建一个临时的,我们会尝试绑定到实际的对象。但是编译器如何知道T::i
是一个你不想最终为其提供定义的左值,在这种情况下,你真正的意思是构建一个临时的并复制它?constexpr
不是类型的一部分,i
的类型只是int const
。你可能需要跨越大量的障碍,甚至试图想出一个措辞来正确地豁免你的static constexpr int i
,但某些成员const int i
。
都是为了解决什么问题?您可以通过+T::i
手动执行左值到右值的转换,并实现同样的效果。或者提供T::i
的定义。
ODR规则已经足够复杂了——你需要一个令人信服的理由在其中钻一个洞。
假设同一个调用发生在两个TU中。函数check
可以采用z
的地址,并且标准保证它在两个调用中看到相同的地址。
除了分配一个存储位置并将i
放在那里之外,您将如何实现这一点?这几乎就是ODR所说的。
- 没有找到相关文章