Неоднозначно, когда два суперкласса имеют функцию-член с тем же именем, но разные подписи
struct A {
void f(int x) {}
};
struct B {
template<typename T> void f(T x) {}
};
struct C : public A, public B {};
struct D {
void f(int x){}
template<typename T> void f(T x) {}
};
int main(int argc, char **argv) {
C c;
c.f<int>(3);
D d;
d.f<int>(3);
}
В чем причина, по которой вызов d.f
прав, но c.f
дает
error: request for member ‘f’ is ambiguous
error: candidates are: template<class T> void B::f(T)
error: void A::f(int)
Ответы
Ответ 1
Первая часть связана с поиском имени участника, поэтому она терпит неудачу.
Я бы назвал вас: 10.2/2 Member name lookup
Следующие шаги определяют результат поиска имени в области класса, C. Во-первых, каждое объявление для имени в классе и в каждом из рассматриваются его под-объекты базового класса. Имя члена f в одном под-объект B скрывает имя члена f в под-объекте A, если A является базой class под-объектом B. Любые декларации, которые так скрыты, исключается из рассмотрения. Каждое из этих заявлений, которое было введенные с помощью декларации использования, считаются от каждого под-объект C, который имеет тип, содержащий объявление обозначенный декларацией использования.
Если результирующий набор объявлений не все из под-объектов тот же тип, или набор имеет нестатический член и включает в себя элементы из отдельных под-объектов существует двусмысленность, и программа плохо формируется. В противном случае этот набор является результатом поиска.
Теперь, что касается функций шаблона.
Согласно 13.3.1/7 Candidate functions and argument list
В каждом случае, когда кандидат является шаблоном функции, кандидат специализированные шаблоны функций генерируются с использованием шаблона вывод аргумента (14.8.3, 14.8.2). Затем эти кандидаты обрабатываются поскольку кандидат действует обычным способом. Данное имя может относиться к одному или больше шаблонов функций, а также к набору перегруженных функции без шаблона. В этом случае функции кандидата созданные из каждого шаблона функции, объединены с набором не-шаблонные функции-кандидаты.
И если вы продолжаете читать 13.3.3/1 Best viable function
F1 считается лучшей функцией, если:
F1 - функция без шаблона, а F2 - шаблон функции специализации
Вот почему следующий фрагмент компиляции и запускает функцию без шаблона без ошибок:
D c;
c.f(1);
Ответ 2
Я считаю, что компилятор предпочитает A::f
(функция без шаблона) над B::f
без всякой причины.
Это скорее компилятор ошибка реализации больше, чем зависящая от реализации деталь.
Если вы добавите следующую строку, то компиляция прекрасна и выбрана правильная функция B::f<>
:
struct C : public A, public B {
using A::f; // optional
using B::f;
};
[Смешно, что до тех пор, пока ::f
не попадут в область C
, они рассматриваются как чуждые функции.]
Ответ 3
Компилятор не знает, какой метод вызывать из класса C, потому что шаблонный метод будет транслироваться в void f (int) в случае типа int, поэтому у вас есть два метода с тем же именем и теми же аргументами, но члены разных родительских классов.
template<typename T> void f(T x) {}
или
void f(int)
попробуйте следующее:
c.B::f<int>(3);
или это для класса A:
c.A::f(3);
Ответ 4
Рассмотрим этот более простой пример:
struct A{
void f(int x){}
};
struct B{
void f(float t){}
};
struct C:public A,public B{
};
struct D{
void f(float n){}
void f(int n){}
};
int main(){
C c;
c.f(3);
D d;
d.f(3);
}
В этом примере, как и у вас, D
компилируется, но C
нет.
Если класс является производным, механизм поиска элементов ведет себя по-разному. Он проверяет каждый базовый класс и объединяет их: в случае C
; Каждый базовый класс соответствует поиску (A:: f (int) и B:: f (float)). После их слияния C
решает, что они неоднозначны.
Для класса case D
: int
выбрана версия вместо float
, потому что параметр является целым числом.
Ответ 5
Что, вероятно, происходит, так это то, что экземпляр шаблона происходит отдельно для классов A
и B
, что заканчивается двумя функциями void f(int)
.
Это не происходит в D
, поскольку компилятор знает о функции void f(int)
как специализацию и поэтому не специализируется на T
для int
.