我有一个有模板的课程:
template<class T = int> class slider;
该类有一个void Process(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();
}
}
如果是,怎么样?
答案 0 :(得分:5)
这样的功能会返回什么?您无法在运行时中更改函数的类型。变体的要点是它的内容是在运行时确定的。
它唯一可以返回的是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
,那么它将会。{/ p>
答案 1 :(得分:4)
(未经测试的代码!)
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);
}
答案 2 :(得分:2)
不,一点也不。你必须访问和处理每种类型的情况。对于访问者而言,这比切换黑客更好。
答案 3 :(得分:1)
这是不可能的,因为boost::variant
无法知道variant
中的所有类型都有共同点。实际上,由于编译器为每个使用的模板特化生成一个不同的类,因此Process()
中每个类型需要使用的boost::variant
函数的地址是不同的。为了解决这个问题,您可以放弃variant
并使用共享基类的虚函数和多态类。