未优化的constexpr的未定义引用用作默认参数

时间:2019-07-17 07:37:53

标签: c++ linker c++14 constexpr undefined-reference

我不明白为什么下面的代码在优化的GCC情况下进行编译,但是在未优化的情况下无法与“对`base :: A_VAL'的未定义引用”链接。我在做躲闪的事吗?这是编译器错误(从来没有)吗?这是Ubuntu上的g ++ 5.4.0。

base.h:

class base {
public:
    static constexpr unsigned int A_VAL{0x69U};
};

derived.h:

#include "base.h"
#include <iostream>

using namespace std;

class derived : public base
{
public:
    int some_func(void) {
        cout << "Some func" << endl;
        return 0;
    }
};

concrete.h:

#include "derived.h"

#include <utility>

class concrete : public derived
{
public:
    concrete(int a, std::pair<unsigned int, unsigned int> data = {A_VAL, A_VAL}) {
        some_func();
        std::cout << "First: " << data.first << " Second: " << data.second << endl;
    }
};

test.cpp:

#include "concrete.h"

int main (int argc, char *argv[])
{
    concrete c{1};

    c.some_func();
}
  

g ++ -O2 -std = c ++ 14 -o test test.cpp

好。

  

g ++ -O0 -std = c ++ 14 -o test test.cpp

/tmp/ccm9NjMC.o: In function `main':
test.cpp:(.text+0x23): undefined reference to `base::A_VAL'
test.cpp:(.text+0x28): undefined reference to `base::A_VAL'
collect2: error: ld returned 1 exit status

2 个答案:

答案 0 :(得分:3)

优化GCC时,可能可以(在内联折叠之后)确定concrete的构造函数的主体可以用

代替
some_func();
std::cout << "First: " << A_VAL << " Second: " << A_VAL << endl;

Since operator<< for the standard stream类按值取整数,并且A_VAL是一个常量表达式,上面的调用不需要A_VAL有任何存储。只需插入其值即可。因此,GCC不需要A_VAL的类外定义,这通常是静态类成员所需的。

当不进行优化时,GCC很可能会初始化对对象。 std::pair's constructor通过引用获取对象,而引用则需要对象绑定。因此,A_VAL的定义是必需的,因此链接程序会抱怨。

您需要在某处定义对象(C ++ 17之前的版本)

// At namespace scope
constexpr unsigned base::A_VAL;

或切换为C ++ 17编译。然后A_VAL(像所有constexpr静态成员数据一样)将隐式为一个内联变量,并且编译器将自行解析其定义。

答案 1 :(得分:0)

我不确定constexpr如何影响此效果,但是您只是声明了静态类变量,但未定义它。即通常,您需要在.cpp文件中的某个位置放置constexpr unsigned int base::A_VAL{0x69U};