下面的代码会触发 gcc '未定义的引用 Foo::d' 和 '未定义的引用 Foo::i' 错误。奇怪的是,只有当我在 -Og 或 -O1 优化模式下编译它时才会发生这种情况,但如果使用 -O2 或 -O3 则不会。此外,如果我将
constexpr double
作为 int&
的参数传递,反之亦然(参见最后一次调用)——它不会触发错误。
#include <stdio.h>
class Foo
{
public:
static constexpr double d = 10.0;
static constexpr int i = 10;
}; //class Foo
void print_double_ref(const double& v)
{
printf("v = %g\n", v);
}
void print_int_ref(const int& n)
{
printf("n = %i\n", n);
}
int main()
{
Foo a;
//This part triggers link error with -Og, -O1
//No error with -O2, -O3
print_double_ref(a.d);
print_int_ref(a.i);
//This part does not trigger link error with -Og, -O1
print_int_ref(a.d);
print_double_ref(a.i);
}
我明白,这个问题在某种程度上与声明函数
print_double_ref
和 print_int_ref
的参数作为引用有关。问题是:
constexpr double
作为 const int&
的参数传递(或 constexpr int
作为 const double&
的参数)不会产生错误?该程序不包含
Foo::i
和 Foo::d
的定义(仅声明),并且这些内容正在被 ODR 使用。因此,该行为是未定义的。
传递给错误的引用参数类型不会触发绑定引用,而是创建一个临时对象,然后将引用绑定到该临时对象。因此,在这种情况下不使用 ODR。