如何简化 boost::static_vistor 的派生类
How to simplify the derived class of boost::static_vistor
template<typename T>
class ClassVariantVisitor : public boost::static_visitor<T>
{
public:
T operator()(int& i) const {
try
{
return boost::lexical_cast<T>(i);
}
catch ( boost::bad_lexical_cast& e)
{
throw e.what();
}
}
T operator()(double& d) const {
try
{
return boost::lexical_cast<T>(d);
}
catch ( boost::bad_lexical_cast& e)
{
throw e.what();
}
}
// ...
};
如您所见,对于每种不同的类型,operator()
的实现代码完全相同。有没有一种实用的方法可以简化代码?
谢谢
根据评论更新//
template<typename T>
class ClassVariantVisitor : public boost::static_visitor<T>
{
public:
T operator()(T& i) const {
try
{
return boost::lexical_cast<T>(i);
}
catch ( boost::bad_lexical_cast& e)
{
throw e.what();
}
}
};
然后编译器(G++(将生成大量错误。
/////根据 iammilind 的评论更新了 2
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/variant.hpp>
#include <boost/lexical_cast.hpp>
using namespace std;
typedef boost::variant<int, double, string> VarIntDoubleString;
// T is the result_type
template<typename T>
class ClassVariantVisitor : public boost::static_visitor<T>
{
public:
template<typename U>
T operator()(U& i) const {
try
{
return boost::lexical_cast<T>(i);
}
catch ( boost::bad_lexical_cast& e)
{
throw e.what();
}
}
};
int main(void)
{
map<string, VarIntDoubleString> mapValuesThree;
// store & retrieve char
mapValuesThree["char_fieldI"] = VarIntDoubleString('c');
char fieldI = boost::apply_visitor(ClassVariantVisitor<char>(), mapValuesThree["char_fieldI"]);
cout << "fieldI: " << fieldI << endl;
}
~/Documents/C++/boost $ g++ -o p192f4 p192f4.cpp -Wall
~/Documents/C++/boost $ ./p192f4
terminate called after throwing an instance of 'char const*'
aborted
~/Documents/C++/boost $ g++ --version
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
致伊米林德: 如您所见,编译器在编译期间不会生成任何错误或警告。
更新 3 基于 Konstantin Oznobihin 的评论
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/variant.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/utility/enable_if.hpp>
using namespace std;
template<typename T>
class ClassVariantVisitor : public boost::static_visitor<T>
{
public:
typedef boost::mpl::vector<int, double, string> VarIntDoubleString;
template <class U>
typename boost::enable_if<
typename boost::mpl::contains<VarIntDoubleString, U>::type, T>::type operator()(U &v) const
{
try
{
return boost::lexical_cast<T>(v);
}
catch ( boost::bad_lexical_cast& e)
{
throw e.what();
}
}
};
int main(void)
{
map<string, ClassVariantVisitor::VarIntDoubleString> mapValuesThree;
// store & retrieve double
mapValuesThree["double_fieldJ"] = ClassVariantVisitor<double>::VarIntDoubleString(2.3456);
double fieldJ = boost::apply_visitor(ClassVariantVisitor<double>(), mapValuesThree["double_fieldJ"]);
cout << "fieldJ: " << fieldJ << endl;
}
我对 boost::mpl 一无所知,也无法使其工作。请参考错误请您告诉我如何更正代码,以便我使用您的想法并使其工作。谢谢
按照 iammilind 的建议使用模板化的运算符 ((,但使用 boost::mpl 过滤类型:
template<typename T>
class ClassVariantVisitor : public boost::static_visitor<T>
{
public:
typedef boost::mpl::vector<int, double> source_types;
template <class U>
typename boost::enable_if<
typename boost::mpl::contains<source_types, U>::type,
T
>::type operator()(U &v) const {
try
{
return boost::lexical_cast<T>(v);
}
catch ( boost::bad_lexical_cast& e)
{
throw e.what();
}
};
更新:如果你有 boost::variant 你可以使用它的嵌套类型序列types
而不是 boost::mpl::vector,并且你不需要在 ClassVariantVisitor 中定义变体,这里有一个基于你的代码的更新解决方案:
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/variant.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/utility/enable_if.hpp>
using namespace std;
typedef boost::variant<int, double, string> VarIntDoubleString;
template<typename T>
class ClassVariantVisitor : public boost::static_visitor<T>
{
public:
template <class U>
typename boost::enable_if<
typename boost::mpl::contains<VarIntDoubleString::types, U>::type, T>::type operator()(U &v) const
{
try
{
return boost::lexical_cast<T>(v);
}
catch ( boost::bad_lexical_cast& e)
{
throw e.what();
}
}
};
int main(void)
{
map<string, VarIntDoubleString> mapValuesThree;
// store & retrieve double
mapValuesThree["double_fieldJ"] = VarIntDoubleString(2.3456);
double fieldJ = boost::apply_visitor(ClassVariantVisitor<double>(), mapValuesThree["double_fieldJ"]);
cout << "fieldJ: " << fieldJ << endl;
}
模板化operator()
:
template<typename U>
T operator()(U& i) const {
try
{
return boost::lexical_cast<T>(i);
}
catch (boost::bad_lexical_cast& e)
{
throw e.what();
}
}
相关文章:
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 在派生函数中指定void*参数
- 如何通过派生类函数更改基类中的向量
- 如何委托派生类使用其父构造函数?
- 如何使用单独文件中的派生类访问友元函数对象
- 派生类销毁的最佳实践是什么
- 如何使用基类指针引用派生类成员
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如何引用基类的派生类?
- 存储模板类型以强制转换回派生<T>
- 需要从 istream 和 ostream 派生 iostream
- 在 C++ 中用派生类型重写成员函数
- 具有多个类、派生类的C++正向声明
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 如果基类包含双指针成员,则派生类的构造函数
- 为什么此派生对象无法访问基类的后递减方法?
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践