在debug或-O1模式下,将constexpr成员作为引用传递会触发链接器错误,并显示gcc

Passing constexpr member as a reference triggers linker error with gcc in debug or -O1 modes

提问人:one_two_three 提问时间:9/7/2023 最后编辑:one_two_three 更新时间:9/7/2023 访问量:47

问:

下面的代码会触发 gcc 'undefined reference Foo::d' 和 'undefined reference Foo::i' 的错误。奇怪的是,只有当我在 -Og 或 -O1 优化模式下编译它时才会发生这种情况,而不是使用 -O2 或 -O3 编译它。此外,如果我作为参数传递,反之亦然(参见最后的调用)——它不会触发错误。constexpr doubleint&

#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_refprint_int_ref

  1. 为什么仅在 -Og 和 -O1 模式下出现链接错误?
  2. 为什么作为参数传递(或作为参数传递)不会产生错误?constexpr doubleconst int&constexpr intconst double&

更新:我知道对于成员来说,应该在类外初始化它们。但是,必须在声明时定义变量。那么为什么允许编译这样的结构呢?static constconstexpr

C++ 逐个引用 constexpr

评论

1赞 wohlstad 9/7/2023
我认为避免链接器错误的正确语法是.请参阅此处:静态成员static inline ...
0赞 alagner 9/7/2023
这与所谓的 ODR 用法(简单来说:通过指针或引用获取地址)有关,该变量仅声明但未定义。拆分定义和声明或使变量内联。看到这个:stackoverflow.com/questions/272900/......
0赞 Marek R 9/7/2023
无法重现:godbolt.org/z/jfd6177sa 您应该提供有关构建过程的更多详细信息。
0赞 wohlstad 9/7/2023
我现在在这里看到,这应该意味着并且因此是一个定义(而不仅仅是一个声明)。所以应该没有链接器错误。这是来自 c++17。您使用哪个版本的 c++?static constexpr int i = 10;inline
1赞 alagner 9/7/2023
@one_two_three有关静态类成员的规则仍然适用,请参阅 stackoverflow.com/a/28446388/4885321 注意:“如果使用了 odr,则该成员仍应在命名空间范围内定义”

答:

2赞 n. m. could be an AI 9/7/2023 #1

该程序不包含 和 的定义(仅包含声明),并且这些东西正在使用 ODR。因此,该行为是未定义的。Foo::iFoo::d

传递给错误的引用参数类型不会触发绑定引用,而是创建临时参数,然后将引用绑定到该参数。因此,在这种情况下不使用ODR。

评论

1赞 one_two_three 9/7/2023
我理解它是为了,但不是 - 没有办法拆分声明和定义。static const doublestatic constexpr doubleconstexpr
1赞 n. m. could be an AI 9/7/2023
@one_two_three godbolt.org/z/6Yfox436c