Подтвердить что ты не робот

Почему 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.

4b9b3361

Ответ 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, чтобы вставлять имена в производные класса, или вы можете явно определить операторы пересылки в производном класс. После того, как имя найдено в производном классе, компилятор останавливается, и не смотрит в базовые классы.