Вызов функции на boost:: option независимо от типа?
У меня есть класс, который имеет шаблон:
template<class T = int> class slider;
Класс имеет void Process(void)
метод, так что, я думаю, он должен вызываться независимо от типа, возвращаемое значение равно void и в нем нет параметров.
На данный момент у меня есть этот код для вызова процесса каждый кадр в моем приложении:
//class menu:
typedef boost::variant<std::shared_ptr<slider<int>>,std::shared_ptr<slider<float>>,std::shared_ptr<slider<double>>,std::shared_ptr<slider<char>>> slider_type;
std::map<std::string,slider_type> Sliders;
//buttons ... etc ...
void Process()
{
if(!Sliders.empty())
{
for(auto i = Sliders.begin(); i != Sliders.end(); ++i)
{
switch(i->second.which())
{
case 0://slider<int>
{
boost::get<std::shared_ptr<slider<int>>>(i->second)->Process();
break;
}
case 1://slider<float>
{
boost::get<std::shared_ptr<slider<float>>>(i->second)->Process();
break;
}
//.....
}
}
}
}
Можно ли выполнить функции Process(), как в следующем примере?
for(auto i = Sliders.begin(); i != Sliders.end(); ++i)
{
switch(i->second.which())
{
boost::get<???Any???>(i->second)->Process();
}
}
Если да, то как?
4 ответа
Что бы могла вернуть такая функция? Вы не можете изменить тип функции во время выполнения. И смысл варианта в том, что его содержимое определяется во время выполнения.
Единственное, что он может вернуть, это boost::any
, Который на самом деле просто обменивает один вид неизвестного на другой (неизвестно, с которым гораздо сложнее иметь дело, когда вы не знаете, что в нем содержится, учтите). Но если вы хотите увидеть такого посетителя:
struct convert_to_any : public boost::static_visitor<boost::any>
{
template<typename T> boost::any operator() (const T& t) {return t;}
};
использование apply_visitor
на этом, и вы получите any
назад. Хотя я не понимаю, как это полезно.
В любом случае, если вы используете get
на variant
Вы почти наверняка делаете неправильные вещи. Правильный способ доступа к элементам варианта - с посетителем, а не с get
,
В вашем случае посетитель должен быть простым:
struct ProcessVisitor : public boost::static_visitor<>
{
template<typename T> void operator() (const T& t) const {t->Process();}
};
Просто используйте apply_visitor
на что. Если вариант содержит тип, который можно использовать с operator->
и возвращаемое значение этой функции может иметь Process
призвал его, тогда будет.
(Непроверенный код!)
struct CallProcess : static_visitor<>
{
template <class T>
void operator()(const T &t) const
{
t->Process();
}
};
for(auto i = Sliders.begin(); i != Sliders.end(); ++i)
{
boost::apply_visitor(CallProcess(), i->second);
}
Нет, совсем нет. Вы должны посетить и разобраться с делом любого типа. Это гораздо лучше сделать с посетителем, чем ваш хакерский ключ.
Это невозможно, потому что boost::variant
не может знать, что все типы в variant
есть что-то общее. Фактически, поскольку компилятор генерирует отдельный класс для каждой используемой специализации шаблона, адрес Process()
Функция, которая должна быть использована, отличается для каждого типа в boost::variant
, Чтобы обойти это вы можете отказаться variant
и использовать виртуальные функции и полиморфные классы, разделяющие общий базовый класс.