Законно ли сделать специализацию шаблона функции виртуальной?
В C++ специализация шаблона функции должна действовать точно так же, как нормальная функция. Значит ли это, что я могу сделать один виртуальный?
Например:
struct A
{
template <class T> void f();
template <> virtual void f<int>() {}
};
struct B : A
{
template <class T> void f();
template <> virtual void f<int>() {}
};
int main(int argc, char* argv[])
{
B b;
A& a = b;
a.f<int>();
}
Visual Studio 2005 выдает мне следующую ошибку:
фатальная ошибка C1001: в компиляторе произошла внутренняя ошибка.
3 ответа
Хорошая ошибка компилятора. Для такого типа проверок я всегда возвращаюсь к компилятору Comeau, прежде чем вернуться к стандарту и проверке.
Comeau C / C++ 4.3.10.1 (6 октября 2008 г. 11:28:09) для ONLINE_EVALUATION_BETA2 Copyright 1988-2008 Comeau Computing. Все права защищены. РЕЖИМ: строгие ошибки C++ C++ 0x_extensions
"ComeauTest.c", строка 3: ошибка: "virtual" не допускается в шаблоне объявления шаблона функции virtual void f(); ^
"ComeauTest.c", строка 10: ошибка: "virtual" не допускается в шаблоне объявления шаблона функции virtual void f(); ^
Теперь, как это было опубликовано другим пользователем, факт в том, что стандарт не позволяет вам определять виртуальные шаблонные методы. Обоснование заключается в том, что для всех виртуальных методов запись должна быть зарезервирована в виртуальной таблице. Проблема в том, что методы шаблона будут определены только тогда, когда они были созданы (использованы). Это означает, что vtable будет иметь разное количество элементов в каждом модуле компиляции, в зависимости от того, сколько разных вызовов f () с разными типами происходит. Тогда ад будет поднят...
Если вам нужна шаблонная функция с одним из аргументов, а одна конкретная версия является виртуальной (обратите внимание на часть аргумента), вы можете сделать это:
class Base
{
public:
template <typename T> void f( T a ) {}
virtual void f( int a ) { std::cout << "base" << std::endl; }
};
class Derived : public Base
{
public:
virtual void f( int a ) { std::cout << "derived" << std::endl; }
};
int main()
{
Derived d;
Base& b = d;
b.f( 5 ); // The compiler will prefer the non-templated method and print "derived"
}
Если вы хотите это обобщить для любого типа, то вам не повезло. Рассмотрим другой тип делегирования вместо полиморфизма (агрегация + делегирование могут быть решением). Дополнительная информация о рассматриваемой проблеме поможет в определении решения.
Согласно http://www.kuzbass.ru:8086/docs/isocpp/template.html ISO / IEC 14882: 1998:
-3- Шаблон функции-члена не должен быть виртуальным.
Пример:
template <class T> struct AA {
template <class C> virtual void g(C); // Error
virtual void f(); // OK
};
Как уже отмечали другие, это не юридический код, потому что шаблон функции-члена не может быть объявлен virtual
,
Тем не менее, даже Visual Studio 2012 задыхается от этого: Нажмите здесь для полного размера
Журналы событий показывают, что компилятор 0xC0000005
, или же STATUS_ACCESS_VIOLATION
, Забавно, как определенная (нелегальная) конструкция кода может сделать компилятор segfault...