C ++ 11成员初始化列表模糊

由于在这个环境中的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 

范围parsing运算符似乎不适用于成员初始化列表,所以我无法弄清楚如何解决歧义。 这个示例编译罚款没有c + + 11标志。

另一种方法是使用大括号:

 version(unsigned major, unsigned minor, unsigned patch) : major{major}, minor{minor}, patch{patch} { } 

然后,macros不会因为它们是类似function的macros而被干扰,并且需要调用括号。

从我自己的编译尝试看来,glibc看起来很愚蠢,并且定义了普通的小写字母。

当我在#include s之后添加以下内容时,它会进行编译。

 #undef major #undef minor 

看起来majorminor是在sys/sysmacros.h定义的macros,由<iostream>引入,这是有问题的,因为这些名称不是为实现保留的 。 注意,如果代码被减less了,我们直接包含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) ^~~~~~~~~~~~~~~~~~~ 

我们可以在下面的bug报告中find这个标识符,主macros扩展到gnu_dev_major :

问题是g ++增加了-D_GNU_SOURCE,major()是_GNU_SOURCE(或_BSD_SOURCE)中的一个macros,或者当没有请求function集时。

包含标题后,您可以随时#undef主要内容。

和:

makedev(),major()和minor()应该是函数,而不是macros。

看起来它们是在sys / sysmacros.h中的GNUC > = 2中引入的,用于向后兼容。 这不是一个好主意。

弄乱macros是很危险的,因为它会污染用户名空间。

所以我们可以看到,macros是一个解决scheme,不幸的是推荐的解决scheme,因为这是一个不会修复的错误:

不会有任何改变。 如果某些代码不喜欢这些macros,请在相应的#include之后添加#undefs。 macros是API的一部分,删除它们只会导致问题。

我们可以在成员初始化器中使用{} ,但是这需要改变参数的types,因为将它们保留为int将是一个不允许的缩小转换。 当然,更名也是一个可能的解决scheme。

更新

我提交了一个glibc错误报告 。 有一些问题,这是否真的是海湾合作委员会或glibc错误,细节是相当复杂的。

/usr/include/sys/sysmacros.h定义了以下macros:

 # define major(dev) gnu_dev_major (dev) # define minor(dev) gnu_dev_minor (dev) # define makedev(maj, min) gnu_dev_makedev (maj, min) 

看起来像你必须打开它们或使用其他名称