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

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

$
0
0

The following 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 the 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 the order of the derived classes is changed to struct D : C<T>, B<T>, then 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 the following 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 22031

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>