在三个文件中考虑这个程序:
// a.h
#include<iostream>
constexpr auto f() {
int i = 0;
auto l1 = [](int& j) { return ++j; };
auto l2 = [](int& j) { return j*=2; };
return l1(i) + l2(i);
}
template<auto V> struct constant {};
inline auto g() {
constexpr auto x = f();
std::ios_base::Init init; // Avoid possible initialization order issues
std::cout << x;
return constant<x>{};
}
static auto x = g();
inline auto y = g();
// a.cpp
#include "a.h"
// main.cpp
#include "a.h"
int main() {
}
其中CCD_ 1和CCD_。我认为g
的定义应该是ODR冲突,因为f()
可以计算为1
或3
,从而更改g()
的返回类型以及它将向std::cout
输出的内容。
然而,在名称查找和重载解析之后,定义中的所有名称都将引用包括a.h
的每个翻译单元中的相同实体,因此我看不出违反了ODR要求中的哪一个。
程序是否违反了一个定义规则。如果是,具体违反了哪一部分?
[basic.def.odr]/6状态:
[…]如果
a.cpp
0的定义满足所有这些要求,那么行为就好像存在D
的单个定义一样。[…]
整个程序的行为必须像只有一个g
副本一样。这意味着,当两个翻译单元被单独编译时,实现(以某种方式(必须确保它不会做任何会使g
的两个副本彼此不可互换的事情,例如为f()
计算两个不同的值。在任何其他情况下,允许实现在某些调用中将f()
求值为1,在其他调用中求值为3(尽管实际实现不太可能做到这一点(,但在这种特殊情况下,它必须确保两个调用返回相同的值。