Quantcast
Channel: Active questions tagged gcc - Stack Overflow
Viewing all articles
Browse latest Browse all 22042

Virtual function overloading in diamond hierarchy produces different results in clang and gcc

$
0
0

Folowing code produces different results on clang.

#include <iostream>

struct Dummy1 {};
struct Dummy2 {};

struct A {
    virtual void foo(Dummy1) {
        std::cout << "A"<< std::endl;
    }
    virtual void foo(Dummy2) {
        std::cout << "A"<< std::endl;
    }
};


template<class T>
struct C : virtual A {
    using A::foo;
    void foo(Dummy2) override {
        std::cout << "C"<< std::endl;
    }   
};


template<class T>
struct B : virtual A {
    using A::foo;
    void foo(Dummy1) final {
        std::cout << "B"<< std::endl;
    }   
};

template<class T>
struct D : B<T>, C<T> {
    // using B<T>::foo; // error: call to member function 'foo' is ambiguous
    // using C<T>::foo; // error: call to member function 'foo' is ambiguous
    using A::foo;
};


int main() {
    D<int> d;
    d.foo(Dummy1{});
    d.foo(Dummy2{});

    A& a = d;
    a.foo(Dummy1{});
    a.foo(Dummy2{});

    B<int>& b = d;
    b.foo(Dummy1{});
    b.foo(Dummy2{});


    C<int>& c =d;
    c.foo(Dummy1{});
    c.foo(Dummy2{});

    return 0;
}

gcc (versions 4.8.1 - 9.1), icc (versions 16, 17, 19), Visual Studio 2017 15.4.0 Preview 1.0, Visual Studio 2013 12.0.31101.00 Update 4, clang (versions 3.4.1 - 3.9.1)

all give following output, which is what I expect:

B
C
B
C
B
C
B
C

Only methods C<T>::foo(Dummy1) and B<T>::foo(Dummy2) are selected, methods A<T>::foo are not used.

Clang (versions 4.0.0 - 8.0.0) selects A::foo(Dummy2) when called through D<T> object and only then. When called through reference to B<T> - C<T>::foo(Dummy2) is selected.

B
A <-- difference
B
C
B
C
B
C

When order of derived classes is changed to struct D : C<T>, B<T>, output changes to:

A <--
C
B
C
B
C
B
C

It seems that for second derived class method foo is not considered virtual.

Only Visual Studio is giving warning with not that helpful C4250.

Writing using B<T>::foo; and using C<T>::foo; in D<T> instead of using A::foo; makes clang produce folowing error: error: call to member function 'foo' is ambiguous. On gcc behavior doesn't change, code compiles and output is the same.

What is correct behavior here?

Since application gives different results, is there a way to find all similar instances of this construction or make some workaround? I have to compile with both gcc and clang. Checking if same problem is present in more places than I found can be hard.


Viewing all articles
Browse latest Browse all 22042

Trending Articles