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

时间:2013-01-16 23:01:01

标签: c++ templates c++11 operators language-lawyer

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

#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;
}

海湾合作委员会汇编并正常运作,但是clang说

  

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

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

谁是对的?


感谢所有帮助我了解GCC行为的人。我提交了一份新的Clang错误报告:

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

1 个答案:

答案 0 :(得分:7)

原始答案:未删除,因为它可能包含有用的信息

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

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

“如果函数是具有一个参数(应为int类型)的成员函数或具有两个参数的非成员函数(第二个参数应为类型) int),它为该类型“

的对象定义后缀增量运算符++

标准似乎没有说明功能模板是否应被视为功能,以解决对合法运营商超载签名的限制(至少,我找不到任何解决这种歧义的句子。只要这是真的,这个问题很难给出明确的答案,我们留下意见

但我想提及此问题的另一个相关方面:一致性

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

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

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

所以我认为答案是GCC是正确的,或者它们都是错的。

<强>更新

@JesseGood和@SethCarnegie正确地指出,每14.7 / 4:

“专门化是实例化或显式专用的类,函数或类成员。”

此外,按照14.6 / 8:

“不能为可以生成有效专业化的模板发出诊断。”

因此,对于问题文本中的运算符函数模板,似乎Clang确实是错误的并且不会产生编译错误