模板类中模板函数的重载
Overloading of template function in template class
我在模板化类中有一个模板化操作符,我想为特定类型更改其行为。我的代码:
#include <iostream>
template <typename N>
struct A {
int x;
template<typename T>
A& operator<<(const T& t) {
x += static_cast<int>(t);
return *this;
}
};
enum class B {
s,t
};
template <typename N>
A<N>& operator<<(A<N>& a, const B& b) {
a.x -= static_cast<int>(b);
return a;
}
int main() {
A<int> a{3};
std::cout << (a<<1).x << " " << (a << B::s).x;
}
g++-4.9编译得很好,但是clang-3.6抱怨它有歧义。
注意,如果类没有模板化,那么两个编译器都可以很好地编译它。
什么是正确的行为?
简短总结:我认为这是gcc在模板部分排序规则中的一个错误,clang是正确的。我提交了错误66914,尽管它可能是错误53499的副本,我直到后来才注意到。
在call
a << B::s;
我们有两个可行的候选人:
template <typename T> A<int>::operator<<(const T& );
template <typename N> operator<<(A<N>&, const B& );
可以重写成员函数,使其以对实例的引用作为第一个参数,并将两者都写为实例化。我们输入:
template <> operator<<(A<int>&, const B& ); // [T = B]
template <> operator<<(A<int>&, const B& ); // [N = int]
既然两者都是可行的候选者,让我们检查一下[over.match]中的规则。来确定哪一个是最可行的候选人:
给定这些定义,一个可行函数F1被定义为比另一个可行函数更好的函数F2如果对于所有参数i, ICSi(F1)不是比ICSi(F2)更差的转换序列,然后
-对于某些参数j, ICSj(F1)是比ICSj(F2)更好的转换序列,或者,如果不是,
不,两者接受完全相同的实参,因此转换序列是相同的。
-上下文是用户自定义转换的初始化[…])
不,无关紧要。
-上下文是一个初始化转换函数[…])
不,无关紧要。
- F1不是函数模板特化,F2是函数模板特化,或者,如果不是,
不,和都是函数模板特化。
- F1和F2是函数模板专门化,F1的函数模板更专门化
根据14.5.6.2中描述的部分排序规则,将F2的模板替换。
这是最复杂的规则。最终,两者都不比另一个更专业。为什么?成员函数有效地:
template <typename T> A<int>& operator<<(A<int>&, const T& );
如果我们为T
(称为Unique1
)合成一个类型,则对自由函数的演绎将失败(因为Unique1
与B
不匹配)。另一方面,如果我们为N
(称为Unique2
)合成了一个类型,则对成员函数的演绎将失败(因为Unique2
与int
不匹配)。
由于这两个函数都没有比另一个函数更专门化,我们已经没有要点了。函数调用应该是不明确的,这是一个gcc bug。
This:
template <typename N>
A<N>& operator<<(A<N>& a, const B& b) {
a.x -= static_cast<int>(b);
return a;
}
不是成员操作符的重载(我确信从标准的角度有更正确的说法),也不是特化,它是参与重载解析的全局模板操作符。
从这个角度来看,两者都是完美匹配的,所以我认为clang是正确的。
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 可以打印矢量和矢量中的矢量的非重载C++函数
- 错误 没有与参数列表匹配的重载函数"getline"实例
- 使用模板重载函数
- C++线程中,没有重载函数接受 X 参数
- std::vector 没有重载函数的实例与参数列表匹配
- C++重载函数,一个采用基类的参数,另一个采用派生类的参数
- 错误:无法解析对重载函数的引用;你的意思是调用它吗?
- 对重载函数find_first_not_of的不明确调用
- 如何从重载解析中删除重载函数?
- CUDA:重载函数"isnan"的多个实例
- C++派生类重载函数(带有 std::function 参数)不可见
- 避免在人为的重载函数调用中拼写出类型
- C++:如何为多个重载函数保留通用代码路径?
- 什么时候可以使用常量装饰调用我的重载函数?
- 尝试使用谓词函数会导致错误:"std::sort"未找到匹配的重载函数
- std::调用,未找到匹配的重载函数
- 为什么在传递长整型时调用具有两个双精度类型的参数的重载函数?
- 为什么使用不匹配的参数调用重载函数仍然有效
- 如何通过签名作为模板参数来解决重载函数?