c++ - 如何修复 `Any` 类代码以正确输出数据?

标签 c++ templates c++17 std template-meta-programming

我正在尝试模拟std::any,我的想法是使用基类指针指向不同类型的模板派生类,来实现存储不同类型数据的功能,就像std::any;因此我编写了以下代码:

class Any {
    TypeBase *_ptr;
    public:
    Any(): _ptr(nullptr) {}
    Any(const Any &other): Any() { _ptr = other._ptr->copy(); }
    Any(Any&& _other): Any() {
        _ptr = _other._ptr;
        _other._ptr = nullptr;
    }
    template<typename T> Any(T&& _data): Any() {
        /*
         * this function attempts to capture rvalue param
         */
        _ptr = new Container<T>(std::forward<T>(_data));
    }
    ~Any() { delete _ptr; }

    template<typename T> T& data_cast() const {
        if (_ptr == nullptr)
            throw std::runtime_error("Container empty");
        return static_cast<Container<T>*>(_ptr)->data;
    }
};

这些工具包类是:

struct TypeBase {
    virtual ~TypeBase() {}
    virtual TypeBase* copy() = 0;
};
template<typename T> struct Container: public TypeBase {
    T data; // those datas will store here
    Container() = delete;
    template<typename U> Container(U&& _data): data(std::forward<U>(_data)) {}
    virtual ~Container() {}
    virtual TypeBase* copy() override { return (new Container<T>(data)); }
};

我的问题是,当我使用这样的代码时,生成的数据不会存储在Container中:

#include <stdexcept>

// paste the definition given above

int main()
{
    double y = 13.32;
    Any a = y;
    std::cout << "The data of 'a' is: " << a.data_cast<double>() << std::endl;
    /* it doesn't work here, only outputs some wrong number */

    return 0;
}

这是我的理解:编译器使用 y 为我隐式构造一个“Any”对象,然后调用复制构造函数来初始化 a

我期望的是“Any”会接受左值和右值数据以减少复制开销,但显然我编写它的方式存在一些我没有意识到的问题。

我尝试使用调试器跟踪进程,发现函数调用过程完全符合我的预期。尽管我可以看到 a 中的指针有效,但输出仍然很奇怪:The data of a is: 3.10818e-317.

我很难找到问题的根源,所以我希望有人指导我,或者也许我只是写了错误的代码,有人可以指出来。

最佳答案

您正在构建一个 Container<double&>但后来将指向它的指针转换到 Container<double>* .

当您将左值传递给转发引用时,模板参数将被推导为引用类型。也就是说,在

template<typename T> Any(T&& _data): Any() {
    _ptr = new Container<T>(std::forward<T>(_data));
}

当你传递左值y时, T推断为 double& 。这样 _data 的类型是 double& && ,折叠为 double& 。如果Tdouble然后_data将是 double&& ,它无法绑定(bind)到左值。


解决方案非常简单:只需应用 std::remove_reference_t :

template <typename T>
Any(T&& data) : Any() {
    using DataT = std::remove_reference_t<T>;
    _ptr = new Container<DataT>(std::forward<T>(data));
}

Demo

关于c++ - 如何修复 `Any` 类代码以正确输出数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77090518/

相关文章:

c++ - 期望引入类型(枚举类)的成员函数的缩写参数

c++ - 获取包含windows系统目录的盘符

c++ - 访问 vector 元素的成员函数时发生访问冲突

c++ - 如果 lambda 在运行时被移动/破坏会发生什么?

c++ - 为什么我不能推断静态成员函数是否存在

c++ - 函数属性是否继承?

c++ - 在 C++ 中的非默认参数之间创建具有默认参数的函数

c++ - 向前声明一个内部类类型,可以吗?

c++ - 基于嵌套 typedef 的存在的类型决定

c++ - 确定模板参数是否为指针