Я пытаюсь использовать boost :: variant с типами шаблонов. Например, у меня есть шаблон типа Tag<T>
, а boost :: variant AnyTag содержит типы, такие как Tag<double>
, Tag<int>
и Tag<std::string>
. Каждый Tag<T>
имеет член типа T. Теперь я хотел бы поставить эти варианты в контейнере и просто присваивать значения во время выполнения, например,Полиморфный сеттер для Boost :: variant
for(AnyTag & tag: AllTags) {
setValue(tag, getValueFromXml());
}
Функция setValue(AnyTag &tag, T &val)
следует использовать тип времени выполнения AnyTag тега чтобы правильно присвоить тегу правильное значение. Моя попытка решить проблему приведена ниже, и она использует другой вариант, который включает только возможные типы T, которые могут быть использованы в AnyTag (TagValueType).
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);
}
К сожалению, этот подход не является то, что я хотел бы, потому что, например, во время компиляции есть не проблема, если я делаю следующее:
AnyTag a = Tag<int>();
setValue(a, double(1.3));
, но во время выполнения, библиотека подталкивания обнаруживает несоответствие типов и сбой программы.
Итак, мое решение является своего рода стиранием типа, которое просто откладывает проблему.
Что бы я хотел иметь, это setValue (AnyTag & tag, T & val), где T - тип времени выполнения AnyTag.
Получаю, что это то, что пытается сделать посетитель варианта, но в этом случае есть проблема, потому что, когда мы строим посетителя, мы должны знать тип, который мы будем использовать.
Любые идеи или любые мысли по этой проблеме?
P.S .: Извините за длинный пост, но я не смог найти способ объяснить мой мыслительный процесс с меньшим количеством слов.
В 'setValue (a, double (1.3))', как вы ожидаете, что компилятор обнаружит проблему, когда проблемой является тип _run-time_ 'a'? – Nemo
Немо, я этого не делаю. Я где-то писал, что то, что я делаю, просто откладывает проблему.То, что я хотел бы иметь это (в "расслабленном" синтаксис): 1) компилятор генерировать SetValue (AnyTag :: Tag &, Int & Вэл) SetValue (AnyTag :: Tag &, двойной и вал) 2) а затем во время выполнения полиморфно выбирает правильный setValue (...) в зависимости от типа времени выполнения AnyTag. –
CuriousNik
Я понимаю, что диспетчеризация не может произойти таким образом на C++, поэтому я подумал, что, возможно, кто-то знает трюк (с шаблоном посетителя), который мог бы решить эту проблему. – CuriousNik