我试图了解强制转换操作符如何使用模板。
请考虑以下代码:
#include <iostream>
using namespace std;
struct S {
int v;
};
class A {
public:
A(void* ptr) : ptr(ptr) {}
void* ptr;
template<typename T>
const T& as() const {
return *static_cast<T*>(ptr);
}
template<typename T>
operator const T&() const {
return as<T>();
}
};
int main() {
S test;
test.v = 123;
A a(&test);
S s = a.as<S>();
S s2 = a; // error here
const S& s3 = a;
cout << s.v << endl;
cout << s2.v << endl;
cout << s3.v << endl;
return 0;
}
gcc给了我以下编译错误:
从'A'转换为非标量类型'S'请求
我知道,我可以通过添加另一个“运算符T()const”解决问题,但为什么编译器在这种情况下无法找到正确的转换?
奇怪的铿锵不抱怨并编译得很好。
(用gcc4.7,gcc4.8和clang3.2测试)
答案 0 :(得分:6)
这是因为使用s2
初始化const S &
需要两次转换;一个用于将引用转换为临时引用,另一个用于将临时值复制到变量中。 C ++只允许一次自动转换。
例如,这也有效:
S s2(a);
因为不再需要创建临时的。
请注意,该标准在此特定情况下有一个段落。在C ++ 03 8.5p14中:
否则(即,对于剩余的复制初始化情况),可以如上所述枚举可以从源类型转换为目标类型或(当使用转换函数时)到其派生类的用户定义的转换序列。在13.3.1.4中,通过重载决策(13.3)选择最好的一个。如果转换不能完成或不明确,则初始化是错误的。选择的函数以初始化表达式作为参数调用;如果函数是构造函数,则调用初始化目标类型的临时函数。然后,根据上述规则,调用的结果(对于构造函数的情况是临时的)用于直接初始化作为复制初始化目标的对象。在某些情况下,允许实现通过将中间结果直接构造到正在初始化的对象中来消除此直接初始化中固有的复制;见12.2,12.8。