在尝试 clang-3.4(从 git 编译)时,它未能编译我的一个项目,在解决重载运算符时抱怨歧义。我发现有两个模板化的运算符,其中一个被声明为成员函数,另一个被声明为非成员函数,两者看起来都非常匹配。
以下 SSCCE 演示了这种情况:
#include <iostream>
struct ostr {
std::ostream& s;
template<class T>
ostr& operator<<(const T& x) { s << x; return *this; }
};
struct xy {
double x, y;
};
template<class Stream>
Stream& operator<<(Stream& s, const xy& x) {
s << "[" << x.x << ", " << x.y << "]";
return s;
}
int main() {
ostr os{std::cout};
xy x{4, 5};
os << "Value is: " << x <<"\n";
}
该项目之前编译得很好,我用几个编译器(、、、和gcc 4.5
)再次检查了这个 SSCCE 4.6
,它们都在没有任何警告的情况下编译它(带)。所有编译器都设置为 C++11/C++0x 标准。将 ctor 添加到 之后,即使在and上也可以正常编译)4.7
4.8
clang 3.3
-Wall -Wextra -pedantic
ostr
MSVC 2012
2010
将两者都operator<<
设为非成员会在所有编译器中表现出歧义(如预期的那样)
在查看了标准草案 (N3242
和N3690
) 之后,我没有找到任何使成员函数/运算符比非成员函数/运算符更匹配的东西。
所以我没能证明clang-3.4
是错的,我想知道谁是对的。因此我的问题是:
- 此代码有效吗?成员运算符/函数是否应该比非成员运算符/函数更好地匹配,这是 clang-3.4 中的一个错误?
- 还是所有其他编译器都错误/过于宽松?
我知道将第二个函数更改operator<<
为非模板函数(std::ostream
而不是模板参数)将解决歧义并按预期工作,但这不是重点。