operator ++作为后缀和前缀不适用于clang

Joh*_*itb 28 c++ templates operators language-lawyer c++11

我试着写一个可以用作前缀和后缀运算符的运算符

#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;
}
Run Code Online (Sandbox Code Playgroud)

GCC编译并且可以正常工作,但是clang说

main.cpp:9:24:error:重载后增量运算符的参数必须是'int'类型(不是'T ...')

void operator++(B, T...) {
Run Code Online (Sandbox Code Playgroud)

谁是对的?


感谢任何帮助我了解GCC行为的人.我提交了一份新的Clang错误报告:

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

And*_*owl 7

原来的答案:(不会被删除,因为它可能包含有用的信息)

我想说这一切都归结为重载的运算符模板是否被认为是一个重载的运算符.从逻辑上讲,我认为情况并非如此,并且Clang是错误的:我认为首先应该选择模板作为基于名称和签名兼容性的重载解析的候选者,然后实例化,然后(可能)选择.我看到它的方式,只有在实例化后,编译器才应检查生成的函数是否具有适当数量的参数.

但那只是我的意见.关于后缀重载的§13.5.7/ 1 operator ++:

"如果函数是带有一个参数的成员函数(应该是int类型)或带有两个参数的非成员函数(第二个应该是int类型),它定义了对象的后缀增量运算符++那种类型"

标准似乎并未阐明功能模板是否应被视为关于合法运算符重载签名限制的函数(至少,我找不到任何解决这种模糊性的句子).只要这是真的,这个问题很难给出明确的答案,我们留下了意见.

但我想提一下这个问题的另一个相关方面:一致性.

虽然问题文本中的代码确实不能在Clang上编译,但以下情况如下:

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

我没有看到两种情况之间存在任何概念上的区别:如果要在实例化之前检查运算符重载的签名,那么上面的定义也不应该编译.如果不是这种情况,那么问题文本中的代码应该编译.

所以我认为答案是海湾合作委员会是正确的,或者他们都错了.

更新:

正如@JesseGood和@SethCarnegie正确指出的那样,每14.7/4:

"专门化是一个实例化或明确专门化的类,函数或类成员."

而且,每14.6/8:

"对于可以生成有效专业化的模板,不应发出诊断信息."

因此,似乎Clang确实是错误的,并且不会在问题的文本中为操作符函数模板生成编译错误.