Код Folowing дает разные результаты на 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 (версии 4.8.1 - 9.1), icc (версии 16, 17, 19), Visual Studio 2017 15.4.0 Preview 1.0, Visual Studio 2013 12.0.31101.00 Обновление 4, clang (версии 3.4.1 - 3.9. 1)
все выдают следующий результат, чего я и ожидаю:
B
C
B
C
B
C
B
C
Выбраны только методы C<T>::foo(Dummy1)
и B<T>::foo(Dummy2)
, методы A<T>::foo
не используются.
Clang (версии 4.0.0 - 8.0.0) выбирает A::foo(Dummy2)
при вызове через объект D<T>
и только затем. При вызове через ссылку на B<T>
- C<T>::foo(Dummy2)
выбран.
B
A <-- difference
B
C
B
C
B
C
Когда порядок производных классов изменяется на struct D : C<T>, B<T>
, вывод изменяется на:
A <--
C
B
C
B
C
B
C
Похоже, что для второго производного класса метод foo
не считается виртуальным.
Только Visual Studio выдает предупреждение, но не очень полезно C4250 .
Запись using B<T>::foo;
и using C<T>::foo;
в D<T>
вместо using A::foo;
заставляет clang выдавать следующую ошибку:
error: call to member function 'foo' is ambiguous
.
На gcc поведение не меняется, код компилируется и вывод одинаков.
Что такое правильное поведение здесь?
Поскольку приложение дает разные результаты, есть ли способ найти все подобные экземпляры этой конструкции или сделать какой-то обходной путь? Я должен скомпилировать как gcc, так и clang. Проверить, присутствует ли та же проблема в большем количестве мест, чем я обнаружил, может быть сложно.