Переопределить спецификатор в качестве параметра шаблона - действительно ли это?

У меня есть следующий фрагмент кода, который не компилируется в Visual С++ 2015, но работает под GCC 4.8.4. Мне интересно, что правильно? Ниже приведен код:

template <class T> class ATemplate;
template <class R, class A1>
    struct ATemplate<R(A1)>{ };

int main()
{
    ATemplate<void(int)> x;
//    ATemplate<void(int)override> y; //---Does not compile!!!
    return 0;
}

Неправильно ли использовать переопределить как спецификатор ниже (или const). Подобный код существует в библиотеке GMock, где расширение макроса используется для генерации параметра шаблона (включая переопределение), а также фактической сигнатуры функции.

Visual С++ 2015 выдает следующую ошибку при удалении пропущенной строки:

x.cpp(11): error C2062: type 'int' unexpected
x.cpp(11): error C2976: 'ATemplate': too few template arguments
x.cpp(4): note: see declaration of 'ATemplate'
x.cpp(11): error C2079: 'y' uses undefined class 'ATemplate'

В одном из приведенных ниже ответов упоминается, что переопределение бессмысленно в контексте свободных функций (действительная точка) - означает ли это, что GCC здесь не так. Спецификатор const также не имеет смысла в этом случае (для бесплатных функций), но тем не менее разрешен (по VС++)??? Кроме того, в нем упоминается, что виртуальные спецификаторы должны присутствовать только в объявлении - это не имеет никакого отношения к этому случаю (поскольку определение отсутствует). Для ключевого слова virtual, это нормально, чтобы пропустить в производном, поскольку не имеет никакого значения, компилируется ли код, но для случая переопределения это не нормально, так как это имеет большое значение.

При использовании метода ReturnType (ArgType arg)... возможного const или переопределить спецификатор в качестве параметра макроса (например, GMock) ограничение, налагаемое VCC, приводит к тому, что этот код не компилируется (очевидно, для Clang тоже). Что правильно?

В стандарте не указано, что спецификатор переопределения не должен использоваться в этом контексте (контекст параметра шаблона?), не так ли?

Ответ 1

Это ошибка g++.

Стандарт разрешает спецификатор virt-sec в двух продуктах: в определении функции (только для определений функций-членов virtual) и в объявлении-члене. Ваш контекст не является ни тем, ни другим.

Более короткая демонстрация поведения глюкометра GCC:

void foo(void) override;          // g++ rejects with message: 
                                  //  virt-specifiers in 'foo' 
                                  //  not allowed outside a class definition
void (*bar)(void) override;       // g++ erroneously accepts
typedef void baz(void) override;  // g++ erroneously accepts

Ответ 2

В соответствии со стандартом спецификатор override является контекстно-зависимым и имеет особое значение только, когда он использовал после объявления функции-члена; в противном случае это не зарезервированное ключевое слово.

Итак, я бы сказал, код в вашем втором примере кажется бессмысленным.

Я попытался скомпилировать оба примера с помощью gcc-5.1.0 (с флагом -S), и они приведут к точно такой же сборке.

Он не компилируется под clang-3.7.0, что приводит к следующей ошибке:

test.cpp:11:23: error: expected '(' for function-style cast or type construction

Pracitcally это означает, что вы не должны использовать переопределение таким образом.

Ответ 3

От 9.2 членов класса (черновик N4140)

virt-specifier-seq:
    virt-specifier
    virt-specifier-seq virt-specifier
virt-specifier:
    override
    final

[9.2/8]

Спецификатор virt-seq должен содержать не более одного из каждого видо-спецификатора. Спецификатор virt-specq появится только в объявление виртуальной функции-члена (10.3).

Итак, насколько я вижу, override не может применяться к свободным функциям, поэтому я не ожидал, что он будет разрешен в сигнатуре/типе свободной функции (даже если она была частью типа например const).