C++11成员初始化列表不明确
C++11 member initialization list ambiguity
由于GNU标准库在这种环境中的实现,我正在努力解决c++11符号解析中的模糊问题:
- Arch Linux 4.2.5-1(x86_64)
- g++5.2.0
- 叮当++3.7.0
示例:
#include <iostream>
#include <string>
struct version {
unsigned major;
unsigned minor;
unsigned patch;
version(unsigned major, unsigned minor, unsigned patch) :
major(major), minor(minor), patch(patch) { }
friend std::ostream & operator<<(std::ostream & out, version const& v) {
out << v.major << ".";
out << v.minor << ".";
out << v.patch;
return out;
}
};
int main(int argc, char ** argv) {
version v(1, 1, 0);
std::cout << v << std::endl;
return 0;
}
编译器错误:
error: member initializer 'gnu_dev_major' does not name a non-static data
member or base class
error: member initializer 'gnu_dev_minor' does not name a non-static data
member or base class
命令:
clang++ -std=c++11 -o test *.cpp
作用域解析运算符似乎不适用于成员初始化列表,所以我不知道如何解决歧义。此示例在没有c++11标志的情况下编译良好。
另一种方法是使用大括号:
version(unsigned major, unsigned minor, unsigned patch) :
major{major}, minor{minor}, patch{patch} { }
这样宏就不会干扰,因为它们是类似函数的宏,需要调用括号。
从我自己的编译尝试来看,glibc似乎在做一些愚蠢的事情,并使用常见的小写单词#define
。
当我在#include
s之后添加以下内容时,它就会编译。
#undef major
#undef minor
看起来major
和minor
是由<iostream>
引入的sys/sysmacros.h
中定义的宏,这是有问题的,因为这些名称不是为实现保留的。请注意,如果代码被缩减,并且我们仅直接包含sys/sysmacros.h
,则会出现相同的问题。
当我在Wandbox上用clang编译这个时,我得到了一个信息更丰富的错误,它让我们可以看到冲突的来源:
usr/include/x86_64-linux-gnu/sys/sysmacros.h:67:21: note: expanded from macro 'major'
# define major(dev) gnu_dev_major (dev)
^~~~~~~~~~~~~~~~~~~
usr/include/x86_64-linux-gnu/sys/sysmacros.h:68:21: note: expanded from macro 'minor'
# define minor(dev) gnu_dev_minor (dev)
^~~~~~~~~~~~~~~~~~~
我们可以在以下错误报告标识符主要宏中找到这一点,该宏扩展到gnu_dev_major:
问题是g++添加了-D_GNU_SOURCE,而major()是一个宏在_GNU_SOURCE中(或_BSD_SOURCE或当没有请求特征集时)。
你总是可以#undef主要后,包括标题。
和:
makedev()、major()和minor()应该是函数,而不是宏。
看起来它们是在sys/symmacro.h中的GNUC>=2中引入的向后兼容性。这不是一个好主意。
篡改宏是危险的,因为它会污染用户名空间。
因此,我们可以看到undef
宏是一个解决方案,不幸的是,它是推荐的解决方案,因为这是一个无法修复的错误:
不会有任何变化。如果某些代码不喜欢宏,请添加#在适当的#include之后不设防。宏是API并删除它们只会导致问题。
我们可以在成员初始化器中使用{}
,但这需要更改参数的类型,因为将它们保留为int将是不允许的缩小转换。当然,更改名称也是一种可能的解决方案。
更新
我提交了一份油嘴滑舌的错误报告。有一些问题是关于这是否真的是一个gcc或glibc错误,细节相当复杂。
/usr/include/sys/sysmacros.h定义了以下宏:
# define major(dev) gnu_dev_major (dev)
# define minor(dev) gnu_dev_minor (dev)
# define makedev(maj, min) gnu_dev_makedev (maj, min)
看起来你必须取消它们的定义或使用其他名称
- Visual C++(VS2017)中用户定义的转换不明确
- 重载类方法的不明确调用
- 为函数定义符号不明确的指针参数
- 父类的私有函数会导致对具有相同名称和相似参数的子类中的公共函数的不明确调用
- 在 C++17 中的命名空间和子命名空间中重载运算符是不明确的
- C++ 编译器错误:P1LinkedList.cpp:145:错误:重载的"to_string(int&)"调用不明确
- 对重载函数find_first_not_of的不明确调用
- 不明确的成员模板查找
- gcc出现不明确的模板实例化错误
- 调用'Node'构造函数是不明确的
- 如何解决不明确的运算符过载问题?
- 对"列表"的引用不明确,包括头文件
- 当接收到不明确的规范时,表示图的邻接列表的数据结构
- 使用列表初始化的不明确构造函数调用
- Rcpp:"运算符="矩阵和列表的不明确重载
- 为什么初始值设定项列表中的元素数会导致不明确的调用错误
- 调用带有支撑init列表的显式构造函数:是否不明确
- C++11成员初始化列表不明确
- 初始值设定项列表构造函数导致右值构造函数不明确
- 列表和字符串之间的不明确构造函数<string>