Законно ли делать специализацию шаблона функции виртуальной? - PullRequest
11 голосов
/ 16 апреля 2009

В 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 ]

20 голосов
/ 16 апреля 2009

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

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

"ComeauTest.c", строка 3: ошибка: «виртуальный» не допускается в функции шаблон декларация шаблон виртуальной пустоты f (); ^

"ComeauTest.c", строка 10: ошибка: «виртуальный» не допускается в функции шаблон декларация шаблон виртуальной пустоты 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"
}

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

4 голосов
/ 16 апреля 2009

Согласно http://www.kuzbass.ru:8086/docs/isocpp/template.html ИСО / МЭК 14882: 1998:

-3- Шаблон функции-члена не должен быть виртуальным.

Пример:

template <class T> struct AA {
    template <class C> virtual void g(C);   //  Error
    virtual void f();                       //  OK
};
1 голос
/ 27 ноября 2012

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

Тем не менее, даже Visual Studio 2012 задыхается от этого: C++ internal compiler error on Visual Studio 2012 Нажмите, чтобы увидеть полный размер

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

...