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.