C++ 11成员初始化列表歧义

Chr*_*son 36 c++ linux c++11

由于此环境中的GNU标准库实现,我正在努力解决c ++ 11符号解析中的模糊问题:

  • Arch Linux 4.2.5-1(x86_64)
  • g ++ 5.2.0
  • clang ++ 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;
}
Run Code Online (Sandbox Code Playgroud)

编译错误:

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
Run Code Online (Sandbox Code Playgroud)

命令:

clang++ -std=c++11 -o test *.cpp
Run Code Online (Sandbox Code Playgroud)

范围解析运算符似乎不适用于成员初始化列表,因此我无法弄清楚如何解决歧义.此示例在没有c ++ 11标志的情况下编译正常.

Joh*_*itb 40

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

version(unsigned major, unsigned minor, unsigned patch) :
  major{major}, minor{minor}, patch{patch} { }
Run Code Online (Sandbox Code Playgroud)

然后宏不会干扰,因为它们是类似函数的宏,需要调用括号.

  • @ChrisHutchinson*"比解开更好的解决方案"*我不知道这个; 它们不应该首先存在,因为它们不是实现保留标识符.我喜欢`#undef`ing他们.(也赞成这一点,因为对于想要使用这些宏的人来说,这是一个有效而干净的解决方案.) (7认同)
  • @BaummitAugen`#undef`ing他们意味着你现在专门围绕非标准定义设计你的代码"不应该在那里"; 这就像你能得到的那样不优雅. (2认同)

Myr*_*ria 19

从我自己的编译尝试来看,看起来glibc正在做一些愚蠢的事情和#define常见的小写字.

当我在#includes 之后添加以下内容时,它会编译.

#undef major
#undef minor
Run Code Online (Sandbox Code Playgroud)


Sha*_*our 15

它看起来像majorminor定义的是宏sys/sysmacros.h正在由引进<iostream>,因为这些名字这是有问题的不是为实现保留.请注意,如果代码减少,我们只是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)
                     ^~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

我们可以在以下错误报告中找到这个记录标识符主要宏扩展为gnu_dev_major:

问题是g ++添加-D_GNU_SOURCE和major()是_GNU_SOURCE(或_BSD_SOURCE或未请求功能集时)中的宏.

在包含标题后,您总是可以#undef major.

和:

makedev(),major()和minor()应该是函数,而不是宏.

它看起来是在sys/sysmacros.h 中的GNUC > = 2中引入的,以实现向后兼容性.这不是一个好主意.

摆弄宏是危险的,因为它会污染用户名空间.

所以我们可以看到undef宏是一个解决方案,不幸的是推荐的解决方案,因为这是一个不会修复bug:

没有变化.如果某些代码不喜欢宏,请在相应的#include之后添加#undefs.宏是API的一部分,删除它们只会导致问题.

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

更新

我提交了一份glibc错误报告.关于这是真的是一个gcc还是一个glibc bug,有一些问题,细节是相关的.

  • 我同意R ..:提交新的错误报告(在上游bugzilla中,而不是Red Hat的:https://sourceware.org/bugzilla/)自2004年以来,glibc维护者对此类事情的态度发生了很大变化. (3认同)

Sla*_*ica 9

/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)
Run Code Online (Sandbox Code Playgroud)

看起来你必须取消它们或使用其他名称