变体实现,如boost :: any,具有自动转换支持

时间:2011-09-06 07:55:30

标签: c++ variant

我想实现一个可以存储任何数据类型(如boost :: any)的变量类,但需要支持数据类型转换。例如,

Variant v1(int(23)); can be converted to bool via v1.get<bool>()
using Conv<int, bool>, Variant v2(CustomT1()); to CustomT2
via Conv<CustomT1, CustomT2> and so on.

这是当前的实现,基于boost :: any:

的想法
#include <iostream>
#include <string>
#include <memory>
#include <stdexcept>

template<typename Src, typename Dest>
struct Conv
{
    /* static? */ Dest convert(const Src& src) const { throw std::runtime_error("type cast not supported"); }
};

template<> struct Conv<int, bool>
{
    bool convert(const int &src) const { return src > 0; } 
};

class IStoredVariant
{};

template<typename T>
struct variant_storage : public IStoredVariant
{
    variant_storage(const T& value) : m_value(value)
    {}

    T&       getValue(void)       { return this->m_value; }
    const T& getValue(void) const { return this->m_value; }

    template<typename U>
    U make_conversion(void) const // just an idea...
    {
        return Conv<U, T>().convert(this->getValue());
    }
protected:
    T m_value;
};

class Variant
{
public:
    template<typename T>
    Variant(const T& value) : m_storage(new variant_storage<T>(value))
    {}

    IStoredVariant&       getImpl(void)       { return *this->m_storage; }
    const IStoredVariant& getImpl(void) const { return *this->m_storage; }

    std::auto_ptr<IStoredVariant> m_storage;

    template<typename T>
    T get(void) const
    {
        const IStoredVariant &var = this->getImpl();
        // ????????????
        // How to perform conversion?
    }

    template<typename T>
    void set(const T &value)
    {
        this->m_storage.reset(new variant_storage<T>(value));
    }
};

int main(void)
{
    Variant v(int(23));
    bool i = v.get<bool>();
}

来自get&lt;&gt;模板方法,我只能访问IStoredVariant指针,但我需要知道具体的类型来选择转换器&lt;&gt;。是否有任何设计模式或解决方法来解决这个问题?

3 个答案:

答案 0 :(得分:2)

这是不可能的。您需要支持虚拟功能中的模板才能实现这一点。

调用上下文中,您只有要转换的类型,并且无法检索存储的类型。在调用上下文中,您只有存储的类型,无法检索要转换的类型。

无法在它们之间传递类型,因此您永远不会同时知道这两种类型,因此无法执行任何转换。

答案 1 :(得分:1)

你的问题很棘手。

如果你丢失了类型信息,那么就无法恢复它(不完全),因为语言本身不支持它(没有反思/内省)。

您仍然可以知道确切的类型,但是无法获得诸如转换为任意类型之类的属性,因为转换机制在编译时被烘焙(取决于构造函数,转换运算符和语言规则)。

如果您只有一小部分您感兴趣的类型,那么Boost.Variant是您最好的选择。

如果你真的想拥有一个完全动态的语言......那么要么放弃C ++,要么在C ++之上重新实现动态语言......

答案 2 :(得分:0)

您可以使用typeid运算符获取变体中存储的类型的类型信息,并将其与typeidT的{​​{1}}进行比较:< / p>

使用此接口定义扩展get

IStoredVariant

将实施添加到具体变体存储:

class IStoredVariant
{
    ...
    type_info getTypeId() = 0; // note the abstract definition
    ...
}

在Variant类中使用它:

template<typename T>
struct variant_storage : public IStoredVariant
{
    ...
    type_info getTypeId() { return typeid(T); }
    ...
}

编辑:您还可以查看不使用class Variant { ... template<typename T> T get(void) const { const IStoredVariant *var = this->getImpl(); if(typeid(T) == var->getTypeId()) { // type matches: cast to the type variant_storage<T>* my_typed_var = static_cast<variant_storage<T>* >(var); // do something with it } } } 的{​​{3}},但查看特定类型的枚举。因此,不支持所有其他类型。