c++ - 用作默认参数的未优化 constexpr 的未定义引用
问题描述
我不明白为什么下面的代码在 GCC 优化下编译,但在未优化时无法链接到“未定义的对 `base::A_VAL' 的引用”。我在做一些狡猾的事情吗?这是编译器错误(从来没有)吗?这是 Ubuntu 上的 g++ 5.4.0。
基地.h:
class base {
public:
static constexpr unsigned int A_VAL{0x69U};
};
派生的.h:
#include "base.h"
#include <iostream>
using namespace std;
class derived : public base
{
public:
int some_func(void) {
cout << "Some func" << endl;
return 0;
}
};
具体.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;
}
};
测试.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.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
解决方案
当优化 GCC 可能能够确定(在内联常量折叠之后)concrete
的构造函数的主体可以被替换为
some_func();
std::cout << "First: " << A_VAL << " Second: " << A_VAL << endl;
由于operator<<
标准流类按值获取整数,并且A_VAL
是一个常量表达式,因此上面的调用不需要为A_VAL
. 它的值只是插入。因此,GCC 不需要A_VAL
像静态类成员通常需要的那样定义类外。
不优化时,GCC 很可能会初始化 pair 对象。std::pair
的构造函数通过引用获取对象,并且引用需要绑定到的对象。因此,定义A_VAL
成为必需,因此链接器抱怨。
您需要在某处定义对象(C++ 17 之前)
// At namespace scope
constexpr unsigned base::A_VAL;
或者切换到编译为 C++17。然后A_VAL
(像所有constexpr
静态成员数据一样)将隐式成为内联变量,编译器将自行解析其定义。
推荐阅读
- c++ - unix读/写如何绑定异步io完成功能进行串口编程?
- spring - Spring Boot @EnableAutoConfiguration 根据属性有条件地排除一个类
- solr - Solr 建议 - 使用 DocumentDictionaryFactory 进行上下文过滤返回整个字段
- xargs - 如何使用重复参数调用 xargs 而参数之间没有空格
- node.js - 笑话:如何加载文件存根?
- ios - Swift 4 将歌曲上传到 Apple Music Library
- c# - 访问 X 上的成员可能会导致运行时异常,因为它是 marshal-by-reference 类的字段
- java - 如何通过可迭代/列表动态链接 Observables?
- r - 基于基于单选按钮的 SliderTextInput 绘图
- arrays - 更改 MongoDB 中集合的根元素