Последние три дня я пытался выяснить, как реализовать универсальный способ получения значения из boost :: variable<…> но это было довольно сложно.
Вот решение, которое я мог бы придумать, но оно совсем не общее:
#include <iostream>
#include "boost\variant\variant.hpp"
using MyVariant = boost::variant<int, std::string>;
class VariantConverter : public boost::static_visitor<>
{
private:
mutable int _int;
mutable std::string _string;
static VariantConverter apply(MyVariant& v)
{
VariantConverter res;
v.apply_visitor(res);
return res; // copy will be elided, right?
}
public:
void operator()(int& i) const
{
_int = i;
}
void operator() (std::string& s) const
{
_string = s;
}
static int to_int(MyVariant v)
{
return apply(v).from_int();
}
static std::string to_string(MyVariant v)
{
return apply(v).from_string();
}
int from_int()
{
return _int;
};
std::string from_string()
{
return _string;
};
};
int main()
{
using namespace std;
MyVariant v = 23;
int i = VariantConverter::to_int(v);
cout << i << endl;
v = "Michael Jordan";
std::string s = VariantConverter::to_string(v);
cout << s.c_str() << endl;
cin.get();
return 0;
}
Буду признателен, если кто-нибудь поможет мне найти лучшее решение.
Или, возможно, кто-то может объяснить мне обоснование этого:
если я объявлю:
using MyVariant = boost::variant<int, std::string>;
а затем:
ConverterToInt : basic_visitor<int> {
public:
int operator() (int i) { return i; };
};
Почему когда я пытаюсь применить ConverterToInt к MyVariant как таковой:
ConverterToInt cti;
MyVariant i = 10;
i.apply_visitor(cti);
Я получаю ошибку компилятора при попытке найти оператор (), который принимает std :: string?
Мне кажется, что apply_visitor пытается вызвать operator () для каждого из типов, которые может принимать MyVariant. Это так? Если это так, почему? Как я могу избежать этого поведения?
Ура!
Вы можете избежать сообщения об ошибке, сказав ConverterToInt
что делать с std::string
, Вы можете знать, что i
не может быть std::string
но не стоит ожидать, что компилятор это знает (и если это правда, почему вы используете вариант?).
apply_visitor
буду называть только правильный operator()
метод, но он решает во время выполнения, и компилятор должен иметь все возможности для генерации кода.
MyVariant iv = 10;
int i = boost::get<int>(iv);
boost :: variable не «вызывает» каждый оператор () интерфейса при вызове, но он должен это делать. Вот и весь смысл. Вариант может содержать любой из типов шаблонов, поэтому, если вы хотите определить операцию над ним, вы должны где-то указать, что эта операция означает для каждого типа.