我不明白为什么下面的代码在优化的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
答案 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};
。