【问题标题】:C++ templated cast operator - conversion from to non-scalar type requestedC++ 模板化强制转换运算符 - 请求从非标量类型转换
【发布时间】:2023-03-30 05:40:01
【问题描述】:

我正在尝试了解 cast 运算符如何使用模板。

考虑以下代码:

#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”

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

奇怪的是clang不抱怨,编译就好了。

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

【问题讨论】:

    标签: c++ templates typecast-operator


    【解决方案1】:

    这是因为用const S &amp; 初始化s2 需要两次转换;一种将引用转换为临时引用,另一种将临时引用复制到您的变量中。 C++ 只允许发生一次自动转换。

    例如,这也有效:

    S s2(a);
    

    因为不再需要创建临时。

    请注意,该标准有一段关于这种特殊情况的段落。在 C++03 8.5p14 中:

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

    【讨论】:

    • 好的,我想我明白了。我只是想 S s2; s2 = 一个;也编译得很好。阅读问题stackoverflow.com/questions/2462773/… 也有帮助,但也显示了编译器之间的显着差异。例如,该问题的代码在 gcc 和 clang 上都失败了。特别是在使用“通过赋值构造”语法时,有谁知道标准所说的和允许的内容?
    • @user1492625:这称为复制初始化。有一段关于这个特殊情况。我会把它添加到我的答案中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 1970-01-01
    • 2015-12-01
    • 1970-01-01
    相关资源
    最近更新 更多