Boost :: variant的多态setter

Cur*_*Nik 5 c++ templates boost

我试图使用boost :: variant与模板类型.例如,我有一个模板类型Tag<T>和升压::变体AnyTag包括类型,如Tag<double>,Tag<int>Tag<std::string>.每个Tag<T>都有类型T的成员.现在,我想将这些变体放在容器中,并在运行时简单地分配值,例如,

for(AnyTag & tag: AllTags) {
    setValue(tag, getValueFromXml()); 
}
Run Code Online (Sandbox Code Playgroud)

该函数setValue(AnyTag &tag, T &val)必须使用AnyTag标记的运行时类型才能正确地为标记分配正确的值.我可以在下面找到解决问题的尝试,并且它使用另一个变体,其中仅包含可以在AnyTag(TagValueType)中使用的可能的T类型.

template<typename T, typename = void>
class Tag {};

template <typename T>
class Tag<T, EnableIf<std::is_arithmetic<T>>> {
public:
    T value = 0;
    std::string address = "";
    T maxValue = std::numeric_limits<T>::max();
    typedef T value_type;
};

template <typename T>
class Tag<T, DisableIf<std::is_arithmetic<T>>> {
public:
    T value;
    std::string address = "";
    typedef T value_type;
};

typedef boost::variant<Tag<std::string>,
                       Tag<double>,
                       Tag<int>,
                      > AnyTag;

typedef boost::variant<std::string, double, int> TagValueType;

class tag_set_value_visitor: public boost::static_visitor<void>
{
    const TagValueType & value;
public:
    tag_set_value_visitor(const TagValueType & val): value(val){}
    template <typename T>
    void operator()(T & tag) const
    {
        tag.value = boost::get<typename T::value_type>(value);
    }
};

inline void setValue(AnyTag & tag, const TagValueType & val) {
    assert(tag.which() == val.which());
    boost::apply_visitor( tag_set_value_visitor(val), tag );
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这种方法不是我想要的,因为例如在编译期间如果我执行以下操作则没有问题:

AnyTag a = Tag<int>();
setValue(a, double(1.3));
Run Code Online (Sandbox Code Playgroud)

但在运行时,boost库会检测到类型不匹配并导致程序崩溃.

所以,我的解决方案是一种类型擦除,只是推迟了问题.

我想要的是一个setValue(AnyTag&tag,T&val),其中T是AnyTag的运行时类型.

我得到的是变体的访问者试图做的,但是在这种情况下存在一个问题,因为当我们构建访问者时,我们必须知道我们将要使用的类型.

关于这个问题的任何想法或想法?

PS:很抱歉很长的帖子,但我找不到用较少的单词来解释我的思考过程的方法.

seh*_*ehe 6

使用¹二进制访问者.

实现operator()除了相应的类型之外什么也不做.

处理不匹配的味道(我返回一个表示成功的布尔值):

Live On Coliru

#include <boost/any.hpp>
#include <boost/variant.hpp>
#include <boost/mpl/vector.hpp>
#include <string>

using namespace boost;

template <typename T>
struct Tag {
    T value;
};

using Types   = mpl::vector<std::string, double, int>;
using Tags    = mpl::transform<Types, Tag<mpl::_1> >::type;

using Variant = make_variant_over<Types>::type;
using AnyTag  = make_variant_over<Tags>::type;

namespace mydetail {
    struct assign_to : boost::static_visitor<bool> {
        template <typename V> bool operator()(Tag<V>& tagged, V const& value) const {
            tagged.value = value;
            return true;
        }

        template <typename T, typename V> bool operator()(T&&, V&&) const {
            return false;
        }
    };
}

bool setValue(AnyTag &tag, Variant const& val) {
    return boost::apply_visitor(mydetail::assign_to(), tag, val);
}

int main() {
    AnyTag t;

    t = Tag<std::string>();

    // corresponding type assigns and returns true:
    assert(setValue(t, "yes works"));

    // mismatch: no effect and returns false:
    assert(!setValue(t, 42));
    assert(!setValue(t, 3.1415926));
}
Run Code Online (Sandbox Code Playgroud)

¹如果我正确理解你的目标.我专注于"我想要的是一个setValue(AnyTag&tag,T&val),其中T是AnyTag的运行时类型." 请求的一部分.