Подтвердить что ты не робот

Operator ++, так как постфикс и префикс не работают с clang

Я попытался написать оператор, который может использоваться как префикс, так и постфиксный оператор

#include <iostream>
#include <utility>

struct B { 
  // ...
};

template<typename ...T>
void operator++(B, T...) {
  std::cout << ((sizeof...(T) == 0) ? "prefix" : "postfix") << std::endl;
}

int main() {
  B b;
  b++;
  ++b;
}

GCC компилируется и отлично работает с этим, но clang говорит

main.cpp: 9: 24: ошибка: параметр перегруженного оператора post-increment должен иметь тип 'int' (не 'T...')

void operator++(B, T...) {

Кто прав?


Спасибо, кто помог мне понять поведение GCC. Я отправил новый отчет об ошибке Clang:

http://llvm.org/bugs/show_bug.cgi?id=14995

4b9b3361

Ответ 1

ОРИГИНАЛЬНЫЙ ОТВЕТ: (не удаляется, так как может содержать полезную информацию)

Я бы сказал, все это сводится к тому, что перегруженный оператор шаблон считается перегруженным оператором или нет. Логически, я бы хотел подумать, что это не так, и Клэн ошибается: я считаю, что шаблон должен быть сначала выбран в качестве кандидата для разрешения перегрузки на основе совместимости имен и подписи, а затем создан, затем (возможно) выбран. Как я вижу это, только после создания экземпляра компилятор должен проверить, имеет ли в результате функция правильное количество аргументов или нет.

Но это только мое мнение. Per § 13.5.7/1 о перегрузке постфикса operator ++:

"Если функция является функцией-членом с одним параметром (который должен иметь тип int) или не-членной функцией с двумя параметрами (второй из которых должен иметь тип int) он определяет оператор приращения postfix ++ для объектов такого типа"

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

Но я хотел бы упомянуть еще один важный аспект вопроса: согласованность.

Хотя верно, что код в тексте вопроса не компилируется на Clang, выполняется следующее:

template<typename... Ts>
int operator + (X x1, Ts... args)
{
    return 0;
}

Я не вижу никакой концептуальной разницы между этими двумя случаями: если сигнатура перегрузки оператора должна быть проверена до создания экземпляра, то указанное выше определение также не должно компилироваться. Если это не так, тогда код в тексте вопроса должен компилироваться.

Итак, ответ на мой взгляд заключается в том, что либо GCC прав, либо они оба ошибаются.

UPDATE:

Как @JesseGood и @SethCarnegie правильно указывают, на 14.7/4:

"Специализация - это класс, функция или член класса, который либо создан, либо явно специализирован".

Кроме того, на 14.6/8:

"Диаграмма не должна выдаваться для шаблона, для которого может быть создана действительная специализация".

Таким образом, кажется, что Clang действительно ошибочен и не возникает ошибка компиляции для шаблона операторской функции в тексте вопроса.