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:
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.
From my own compilation attempt, it looks like glibc is doing something stupid and #define
ing common lowercase words.
When I add the following after the #include
s, it compiles.
#undef major
#undef minor
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.
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.
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:
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:
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).
You can always #undef major after including headers.
and:
makedev(), major() and minor() should be functions, not macros.
It looks they were introduced in GNUC >= 2 in sys/sysmacros.h for backward compatibility. It is not a good idea.
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:
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With