c++ 11成员初始化列表不明确

时间:2023-01-15 17:43:15

I am struggling with what appears to be an ambiguity in c++11 symbol resolution due to the GNU standard library implementation in this environment:

在c++11中,由于GNU标准库在这种环境下的实现,出现了一些模棱两可的地方,我正在努力解决:

  • Arch Linux 4.2.5-1 (x86_64)
  • Arch Linux 4.2.5-1(x86_64)
  • g++ 5.2.0
  • g++ 5.2.0
  • clang++ 3.7.0
  • 铿锵声+ + 3.7.0

Example:

例子:

#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;
}

Compiler error:

编译错误:

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

Command:

命令:

clang++ -std=c++11 -o test *.cpp

The scope resolution operator does not appear to be applicable in member initialization lists so I can't figure out how to resolve the ambiguity. This sample compiles fine without the c++11 flag.

范围解析操作符似乎不适用于成员初始化列表,因此我无法找到如何解决歧义。这个示例在没有c++11标志的情况下编译良好。

4 个解决方案

#1


40  

Another way is to use braces:

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

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

Then the macros will not interfere because they are function-like macros and need parentheses to be invoked.

这样宏就不会受到干扰,因为它们是类函数的宏,需要调用圆括号。

#2


19  

From my own compilation attempt, it looks like glibc is doing something stupid and #defineing common lowercase words.

从我自己的编译尝试来看,glibc似乎在做一些愚蠢的事情,并且#定义普通的小写单词。

When I add the following after the #includes, it compiles.

当我在#include之后添加以下内容时,它将被编译。

#undef major
#undef minor

#3


15  

It looks like major and minor are macros defined in sys/sysmacros.h which is being brought in by <iostream>, which is problematic since these names are not reserved for the implementation. Note if the code is reduced and we solely include sys/sysmacros.h directly the same problem will occur.

看起来大调和小调都是在sys/sysmacros中定义的宏。h是由 引入的,这是有问题的,因为这些名称并不是为实现预留的。注意,如果代码被缩减,并且我们只包含sys/sysmacros。同样的问题会直接发生。

When I compile this with clang on Wandbox I get this more informative error which allows us to see where the conflict is coming from:

当我用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)
                     ^~~~~~~~~~~~~~~~~~~

We can find this documented in the following bug report identifier major macro expanded into gnu_dev_major:

我们可以在下面的bug报告标识符主要宏扩展到gnu_dev_major中找到这个文档。

The problem is that g++ adds -D_GNU_SOURCE and major() is a macro in _GNU_SOURCE (or _BSD_SOURCE or when no feature set is requested).

问题是,g++添加-D_GNU_SOURCE和major()是_GNU_SOURCE中的宏(或_BSD_SOURCE,或者在不请求特性集时)。

You can always #undef major after including headers.

在包含标题之后,您总是可以使用#undef major。

and:

和:

makedev(), major() and minor() should be functions, not macros.

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

It looks they were introduced in GNUC >= 2 in sys/sysmacros.h for backward compatibility. It is not a good idea.

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

Fiddling with macros is dangerous since it pollutes user name space.

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

and so we can see undef the macros is one solution and it is unfortunately the recommended solution since this is a won't fix bug:

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

There will be no change. If some code does not like the macros, add #undefs after the appropriate #include. The macros are part of the API and removing them only causes problems.

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

We could use {} in the member intializer but this requires changes the types of the parameters since leaving them as int would be a narrowing conversion which is not allowed. Of course changing names is also a possible solution.

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

Update

更新

I filed a glibc bug report. There is some questions about whether this is really a gcc or a glibc bug, the details are rather involved.

我提交了一个glibc错误报告。关于这到底是gcc还是glibc bug,有一些问题,细节很复杂。

#4


9  

/usr/include/sys/sysmacros.h has following macros defined:

/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)

looks like you have to undef them or use other names

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

#1


40  

Another way is to use braces:

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

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

Then the macros will not interfere because they are function-like macros and need parentheses to be invoked.

这样宏就不会受到干扰,因为它们是类函数的宏,需要调用圆括号。

#2


19  

From my own compilation attempt, it looks like glibc is doing something stupid and #defineing common lowercase words.

从我自己的编译尝试来看,glibc似乎在做一些愚蠢的事情,并且#定义普通的小写单词。

When I add the following after the #includes, it compiles.

当我在#include之后添加以下内容时,它将被编译。

#undef major
#undef minor

#3


15  

It looks like major and minor are macros defined in sys/sysmacros.h which is being brought in by <iostream>, which is problematic since these names are not reserved for the implementation. Note if the code is reduced and we solely include sys/sysmacros.h directly the same problem will occur.

看起来大调和小调都是在sys/sysmacros中定义的宏。h是由 引入的,这是有问题的,因为这些名称并不是为实现预留的。注意,如果代码被缩减,并且我们只包含sys/sysmacros。同样的问题会直接发生。

When I compile this with clang on Wandbox I get this more informative error which allows us to see where the conflict is coming from:

当我用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)
                     ^~~~~~~~~~~~~~~~~~~

We can find this documented in the following bug report identifier major macro expanded into gnu_dev_major:

我们可以在下面的bug报告标识符主要宏扩展到gnu_dev_major中找到这个文档。

The problem is that g++ adds -D_GNU_SOURCE and major() is a macro in _GNU_SOURCE (or _BSD_SOURCE or when no feature set is requested).

问题是,g++添加-D_GNU_SOURCE和major()是_GNU_SOURCE中的宏(或_BSD_SOURCE,或者在不请求特性集时)。

You can always #undef major after including headers.

在包含标题之后,您总是可以使用#undef major。

and:

和:

makedev(), major() and minor() should be functions, not macros.

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

It looks they were introduced in GNUC >= 2 in sys/sysmacros.h for backward compatibility. It is not a good idea.

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

Fiddling with macros is dangerous since it pollutes user name space.

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

and so we can see undef the macros is one solution and it is unfortunately the recommended solution since this is a won't fix bug:

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

There will be no change. If some code does not like the macros, add #undefs after the appropriate #include. The macros are part of the API and removing them only causes problems.

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

We could use {} in the member intializer but this requires changes the types of the parameters since leaving them as int would be a narrowing conversion which is not allowed. Of course changing names is also a possible solution.

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

Update

更新

I filed a glibc bug report. There is some questions about whether this is really a gcc or a glibc bug, the details are rather involved.

我提交了一个glibc错误报告。关于这到底是gcc还是glibc bug,有一些问题,细节很复杂。

#4


9  

/usr/include/sys/sysmacros.h has following macros defined:

/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)

looks like you have to undef them or use other names

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