考虑这个非常简单的例子,其中我有一个模板包装类,其中定义了操作符:
template <class T>
struct W {
W(const T&) {}
};
template <class T>
T operator + (const W<T>& w1, const W<T>& w2) { return T(); }这令人惊讶地无法与包装类型匹配,而gcc4.5.1中的简单错误无法找到operator + (A,A)
struct A {};
int main() {
A a1, a2;
A a3 = a1 + a2;
}我尝试通过测试非模板包装器来找到原因,但是这个版本有效:
struct A {};
struct WA {
WA(const A&) {}
};
A operator + (const WA& w1, const WA& w2) { return A(); }
int main() {
A a1, a2;
A a3 = a1 + a2;
}参数匹配差异的原因是什么,如何使模板版本工作?
更新
我把你的答案考虑进去了,我把这个例子改成了一个相反的例子,结果仍然是一样的--模板版本是在抱怨缺少操作符+,而非模板工作得很好。现在,我有了显式包装类的显式强制转换操作符:
模板版本
template <class T>
struct W {
};
template <class T>
T operator + (const W<T>& w1, const W<T>& w2) { return T(); }
struct A {
operator W<A>() const { return W<A>(); }
};非模板
struct WA {
};
struct A {
operator WA() const { return WA(); }
};
A operator + (const WA& w1, const WA& w2) { return A(); }我试图避免这种解决办法:
A a3 = W(a1) + W(a2);这没希望了吗?
A a3 = a1 + a2;发布于 2012-10-05 11:58:20
模板参数演绎在过载解析之前。但是模板参数演绎不考虑隐式转换,因此模板化运算符甚至从未被考虑过。
隐式转换仅在选择过载后应用。
不过你可以说是A a3 = W(a1) + W(a2);。
发布于 2012-10-05 12:05:18
您的第一个示例失败了,因为标准说它必须在模板中失败。与参数相关的名称查找存在潜在问题,而模板则加剧了这些问题。其中一种方法是防止模板进行这种查找,除非您对模板的使用有明确的了解。以下是C++03标准14.8.1节第6段的相关案文:
对于简单的函数名,即使函数名在调用的范围内不可见,参数依赖的查找(3.4.2)也适用。这是因为调用仍然具有函数调用的语法形式(3.4.1)。但是,当使用带有显式模板参数的函数模板时,调用没有正确的语法形式,除非在调用点上有一个具有该名称的函数模板。如果没有这样的名称是可见的,则调用在语法上不具有良好的格式,并且不适用与参数相关的查找。如果这样的名称是可见的,则会应用与参数相关的查找,并在其他命名空间中找到其他函数模板。
更新:
这一问题是经过编辑的,并附有补充资料。
我试图避免这种解决办法:
A a3 = W(a1) + W(a2);
你为什么要避免这种情况?您的这段代码违反了编程的两个关键规则。
即使你的非模板版本也违反了这些规则。您可以通过(隐藏)转换到不相关的类( a1+a2 )来计算W,该类的operator+返回A而不是W。这并不是最不惊讶的原则。至少可以说,这是令人吃惊的。为什么你不认为将你的转换明确化是一个更好的方法呢?
与参数相关的查找是一个非常强大的工具,但是与此功能相关的问题很多。将ADL与自动类型转换结合起来,使问题放大。将其与自动类型转换和模板相结合,就会造成混乱。标准委员会认为已经够了。除非将转换显式化,否则不能执行想要做的事情。
https://stackoverflow.com/questions/12745569
复制相似问题