简体   繁体   中英

Multiple inheritance from instantiations of template class and what about access to member functions

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM