GCC/VS2008: различное поведение вызова функции, когда шаблонный базовый класс получен от самого себя
Следующий код работает с Visual Studio 2008, но не с GCC/g++ 4.3.4 20090804. Какое поведение - согласно стандарту С++ - правильно?
template <int N>
struct A : A<N-1> {};
template <>
struct A<0> {};
struct B : A<1> {};
template <int N>
void Func(const A<N> &a) {}
int main()
{
A<1> a; //is derived from A<0>
Func(a); //vs2008: ok, g++: ok
//Comeau: ok
B b; //is derived from A<1>
Func(b); //vs2008: ok, g++: error, no matching function for call to Func(B&)
//Comeau: error: no instance of function template "Func" matches the
// argument list. The argument types that you used are: (B).
return 0;
}
Если я перегружаю Func() с помощью
void Func(const A<0> &a) { std::cout << '0'; }
void Func(const A<1> &a) { std::cout << '1'; }
всегда последний называется (как и ожидалось). Поэтому я также ожидал бы, что шаблонную функцию вызывать с N = 1, потому что A < 1 > является прямой базой B. Это предположение действительно неверно?
Ответы
Ответ 1
После некоторого копания через N3035 я нашел это в разделе 14.9.2.1.4:
Если P - класс, а P имеет вид simple-template-id, то преобразованный A может быть производным классом выведенного A. Аналогично, если P является указателем на класс формы simple-template- id, преобразованный A может быть указателем на производный класс, на который указывает выведенный A.
Однако в пункте 14.9.2.1.5 говорится:
Эти альтернативы рассматриваются только в том случае, если вычет типа в противном случае не будет выполнен. Если они дают более одного возможного выведенного А, то вывод типа терпит неудачу.
В этом случае: A<1>
и A<0>
считаются базовыми классами для B
.
Я предполагаю, что это означает отсутствие для Visual Studio (по крайней мере, если текущий стандарт говорит то же самое: упражнение для читателя).
Ответ 2
В ИСО/МЭК 14882 это почти то же самое (14.8.2.1):
- Если P - класс, а P имеет форму template-id, то A может быть производный класс выведенного A. Аналогично, если P является указателем на класс формы template-id, A может быть указатель на производный класс, указывающий на по выведенному А.
Эти алютивы рассматриваются только в том случае, в противном случае потерпит неудачу Если они уступят более чем один возможный вывод A, вывод типа не выполняется.
Итак, я согласен с Яном. Кто-нибудь здесь, кто этого не делает?