Let's take a look at the code:
template <typename C>
class S {
public:
void add (C c) { ++cnt; }
size_t size () const { return cnt; }
private:
size_t cnt {};
};
struct Foo1 {};
struct Foo2 {};
struct Foo3 {};
class Z : public S<Foo1>, public S<Foo2>, public S<Foo3> {
public:
using S<Foo1>::add;
using S<Foo2>::add;
using S<Foo3>::add;
using S<Foo1>::size; // (1)
using S<Foo2>::size; // (2)
using S<Foo3>::size; // (3)
};
And usage looks like this:
Z z;
z.add (Foo1 {});
z.add (Foo1 {});
z.add (Foo2 {});
cout << z.size () << endl;
This code compiles fine with gcc-5.1 (c++11), but this code does not compile under clang-3.5 (c++11 - sorry, I do not have newer version of clang).
Clang produces "error: call to member function 'size' is ambiguous" which is basically (from my point of view) correct, but gcc compiles it and returns 2 .
Ok, but here is much more fun, if I switch the order of lines marked with comments (1) and (2), to get something like this:
using S<Foo2>::size; // (2)
using S<Foo1>::size; // (1)
The code still compiles on gcc and the result is: 1 .
As you can imagine, if you write line (3) before these two, you will get 0 .
So, from what I see, gcc gets first using declaration of S<C>::size , ignores rest of them and uses this one.
Could anybody tell me which compiler is doing correct work according to the C++ standard?
Reported at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66698
Best, Artur
It's a gcc bug. Clang and MSVC correctly flag the ambiguity.
If you remove the 3 using statements, the compilation fails (as it should) because of ambiguity:
prog.cpp:39:12: error: request for member 'size' is ambiguous
cout << z.size () << endl; return 0;
^
prog.cpp:9:12: note: candidates are: size_t S<C>::size() const [with C = Foo3; size_t = unsigned int]
size_t size () const { cout<<typeid(C).name()<<endl; return cnt; }
^
prog.cpp:9:12: note: size_t S<C>::size() const [with C = Foo2; size_t = unsigned int]
prog.cpp:9:12: note: size_t S<C>::size() const [with C = Foo1; size_t = unsigned int]
According to the standard member lookup algorithm, despite the using decalartions you should come to the same results:
10.2/3: (...) In the declaration set, using-declarations are replaced by the members they designate, and type declarations (including injected-class-names) are replaced by the types they designate.
I couldn't find an exact match for this bug. I'd suggest that you report it .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.