C++模板化转换运算符 - 从请求转换为非标量类型

use*_*625 4 c++ templates typecast-operator

我试图了解强制转换操作符如何使用模板.

请考虑以下代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

gcc给我以下编译错误:

请求从'A'转换为非标量类型'S'

我知道,我可以通过添加另一个"运算符T()const"来解决问题,但为什么编译器在这种情况下无法找到正确的转换?

奇怪的铿锵不抱怨并编译得很好.

(用gcc4.7,gcc4.8和clang3.2测试)

Vau*_*ato 6

这是因为初始化s2const S &需要两个转换; 一个用于将引用转换为临时引用,另一个用于将临时值复制到变量中.C++只允许一次自动转换.

例如,这也有效:

S s2(a);
Run Code Online (Sandbox Code Playgroud)

由于不再需要创建临时.

请注意,该标准在此特定情况下有一个段落.在C++ 03 8.5p14中:

否则(即,对于剩余的复制初始化情况),可以如13.3中所述枚举可以从源类型转换为目的地类型或(当使用转换函数时)到其派生类的用户定义的转换序列. 1.4,通过重载决策(13.3)选择最好的一个.如果转换不能完成或不明确,则初始化是错误的.选择的函数以初始化表达式作为参数调用; 如果函数是构造函数,则调用初始化目标类型的临时函数.然后,根据上面的规则,调用的结果(对于构造函数的情况是临时的)用于直接初始化作为复制初始化目标的对象.在某些情况下,通过将中间结果直接构造到正在初始化的对象中,允许实现消除这种直接初始化中固有的复制; 见12.2,12.8.