Почему GCC не может устранить множественные унаследованные функции (тем не менее, clang can)?
Возможный дубликат:
Почему многонаследованные функции с одинаковым именем, но разные подписи не могут рассматриваться как перегруженные функции?
Это не скомпилируется в указанном месте с помощью g++ 4.6.1:
enum Ea { Ea0 };
enum Eb { Eb0 };
struct Sa { void operator()(Ea) {} };
struct Sb { void operator()(Eb) {} };
struct Sbroken : Sa, Sb {};
struct Sworks {
void operator()(Ea) {}
void operator()(Eb) {}
};
int main() {
Sworks()(Ea0);
Sbroken()(Ea0); // g++ can't disambiguate Ea vs. Eb
}
Clang 2.8 компилирует этот код, что делает меня неопределенным, если код действительно действителен С++ или нет. Я собирался сделать оптимистично, что clang был прав, а g++ был неправильным, но затем я сделал небольшое изменение, которое сделало clang аналогичной ошибкой:
enum Ea { Ea0 };
enum Eb { Eb0 };
struct Sa { void f(Ea) {} };
struct Sb { void f(Eb) {} };
struct Sbroken : Sa, Sb {};
struct Sworks {
void f(Ea) {}
void f(Eb) {}
};
int main() {
Sworks().f(Ea0);
Sbroken().f(Ea0); // both clang and g++ say this is ambiguous
}
Единственное изменение, которое я сделал, заключалось в использовании именованной функции f
, а не operator()
. Я не понимаю, почему это имеет значение, но это так: эта версия не компилируется с g++ или с clang.
Ответы
Ответ 1
Я думаю, что это имеет какое-то отношение к сокрытию функций в базовых классах, а сообщение об ошибке GCC, похоже, мало помогает, даже если вы используете struct
вместо enum
: на самом деле, сообщение об ошибке вводит в заблуждение, так как теперь Ea
и Eb
являются двумя разными классами, причем не подразумевается преобразование от Ea
до Eb
, двусмысленность не должна возникать, но GCC похоже, не согласен со мной: http://ideone.com/cvzLW (см. также модификацию).
В любом случае, если вы введете функции в область класса, явным образом написав using
как:
struct Sbroken : Sa, Sb
{
using Sa::operator();
using Sb::operator();
};
тогда он работает: http://ideone.com/LBZgC
То же самое и с другим примером:
struct Sbroken : Sa, Sb
{
using Sa::f;
using Sb::f;
};
Код: http://ideone.com/3hojd
Ответ 2
Попытка понять фактический текст в стандарте (§10.2) непросто,
но есть пример, который дает понять: поиск имени для имени x
в производном классе не выполняется, если имя отсутствует в производном
класс, но он присутствует в нескольких базовых классах, и это не
скрытый. (Скрытый здесь не имеет значения, поскольку он вмешивается только тогда, когда виртуальный
наследование присутствует.) Насколько я могу судить, это так
независимо от имени участника; Я не могу найти исключения, если
член имеет специальное имя operator()
. перегрузка
разрешение не вступает в игру, потому что их отказ в имени
поиск, прежде чем набор перегрузки будет полностью построен. я точно уверен
что оба фрагмента кода являются незаконными и что есть ошибка в
лязг.
Вы можете использовать объявления using
, чтобы вставлять имена в производные
класса, или вы можете явно определить операторы пересылки в производном
класс. После того, как имя найдено в производном классе, компилятор останавливается,
и не смотрит в базовые классы.