Законно ли делать виртуальную специализацию шаблона функции?

В 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: в компиляторе произошла внутренняя ошибка.


person alexk7    schedule 16.04.2009    source источник
comment
Хорошее сообщение об ошибке! Возможно, отправьте его в MS Connect, даже если ваш код незаконен, сообщение должно быть лучше.   -  person Lucero    schedule 16.04.2009
comment
Я не знаю наверняка, поэтому я не публикую это как настоящий ответ, но готов поспорить, что это незаконно, так как vtable в конечном итоге будет отличаться в разных единицах компиляции, которые вызывали функцию с разными типами (или вообще не называл).   -  person rmeador    schedule 16.04.2009
comment
gcc дает множество сообщений об ошибках, начиная с testtemp.cpp: 4: error: явная специализация в области, не относящейся к пространству имен, `struct A '   -  person veefu    schedule 16.04.2009
comment
это не может быть законным, потому что вы не можете специализироваться в определении класса. и сделать шаблон виртуальным тоже не получится, потому что шаблоны не могут быть виртуальными.   -  person Johannes Schaub - litb    schedule 16.04.2009
comment
Я заполнил ошибку в MS Connect: connect.microsoft.com/VisualStudio/ обратная связь /   -  person alexk7    schedule 16.04.2009


Ответы (3)


Хорошая ошибка компилятора. Для этого типа проверок я всегда возвращаюсь к компилятору Comeau перед тем, как вернуться к стандарту и проверить.

Comeau C / C ++ 4.3.10.1 (6 октября 2008 г., 11:28:09) для ONLINE_EVALUATION_BETA2 Авторские права 1988-2008 Comeau Computing. Все права защищены. РЕЖИМ: строгие ошибки C ++ C ++ 0x_extensions

"ComeauTest.c", строка 3: ошибка: "virtual" не допускается в шаблоне объявления шаблона функции virtual void f (); ^

«ComeauTest.c», строка 10: ошибка: «virtual» не допускается в шаблоне объявления шаблона функции virtual void f (); ^

Теперь, когда это было опубликовано другим пользователем, факт в том, что стандарт не позволяет вам определять виртуальные шаблонные методы. Причина в том, что для всех виртуальных методов запись должна быть зарезервирована в vtable. Проблема в том, что методы шаблона будут определены только после того, как они будут созданы (использованы). Это означает, что 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"
}

Если вы хотите, чтобы это было обобщено для любого типа, то вам не повезло. Рассмотрим другой тип делегирования вместо полиморфизма (решением может быть агрегация + делегирование). Дополнительная информация о проблеме поможет в поиске решения.

person David Rodríguez - dribeas    schedule 16.04.2009
comment
обратите внимание на звонок в b.f ‹int› (5); создаст специализацию, которая не является виртуальной, и назовет ее. Поскольку вы перегрузили шаблон не шаблоном, вызов предпочтет не шаблон. но если позвонить b.f ‹int› (5); он по-прежнему будет вызывать не виртуальную функцию. - person Johannes Schaub - litb; 16.04.2009
comment
Тем не менее, конечно, перегрузка - это лучший вариант. Фактически, в книге «Стандарты кодирования C ++» есть одно правило - избегать явной специализации шаблона функции, потому что она ограничена, а перегрузка предоставляет превосходную альтернативу. - person Johannes Schaub - litb; 16.04.2009
comment
Я пытаюсь определить функцию GetValue, которая будет возвращать значение типа T. T всегда из известного набора типов. Я хочу иметь возможность вызывать функцию из шаблонов без необходимости давать каждой версии другое имя. - person alexk7; 16.04.2009
comment
Мой обходной путь сейчас - использовать параметр out, чтобы разрешение перегрузки могло соответствовать ему, но я хотел знать, возможно ли это. - person alexk7; 16.04.2009
comment
alexk7, простой способ - это оболочка типа-к-типу: virtual int getv (type_ ‹int›); виртуальный bool getv (type_ ‹bool›); а type_ - это шаблон ‹typename T› struct type_ {}; и позвоните с помощью b.getv (type_ ‹T› ()); теперь перегрузка разберется, что вызывать, без шаблонов, а с виртуальным :) - person Johannes Schaub - litb; 16.04.2009
comment
Спасибо за идею! Я все еще могу использовать шаблон в базовом классе, чтобы скрыть использование type_: template ‹class T› T getv () {return getv (type_ ‹T› ()); } - person alexk7; 16.04.2009
comment
Кто-нибудь знает, есть ли какие-либо обновления по этой теме в C ++ 20? - person Jarek C; 29.10.2020

Согласно 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
};
person veefu    schedule 16.04.2009

Как отмечали другие, это недопустимый код, потому что нельзя объявить шаблон функции-члена virtual.

Но даже Visual Studio 2012 подавляется этим: Внутренняя ошибка компилятора C ++ в Visual Studio 2012 Нажмите здесь, чтобы увидеть полный размер

Журналы событий показывают, что компилятор разбился на 0xC0000005 или STATUS_ACCESS_VIOLATION. Забавно, как некоторая (незаконная) конструкция кода может привести к сбою компилятора ...

person bwDraco    schedule 27.11.2012