题
我需要开始使用代码,因为我不知道该用什么术语。可以说我有以下代码:
class Node
{
public:
void Parse(rapidxml::xml_node<> *node)
{
for (rapidxml::xml_attribute<> *attr = node->first_attribute();
attr;
attr = attr->next_attribute())
{
std::stringstream converter;
converter << attr->value();
if( !strcmp(attr->name(), "x") ) converter >> x;
else if( !strcmp(attr->name(),"y") ) converter >> y;
else if( !strcmp(attr->name(), "z") ) converter >> z;
}
}
private:
float x;
float y;
float z;
};
我不能忍受的是,如果(STRCMP(attr->名称(), “X”)!)转换器>> X的重复;我觉得这是很容易出错和单调,但我想不出另一种方式来映射一个字符串值的成员分配。什么是一个才能避免代码一些其他的方法,比如这个?唯一的其他可能的替代我能想到的是使用一个HashMap,但运行到与回调的问题
这是我所能了最好的,但它不是那么灵活,我想:
class Node
{
Node() : x(0.0f), y(0.0f), z(0.0f)
{
assignmentMap["x"] = &x;
assignmentMap["y"] = &y;
assignmentMap["z"] = &z;
}
public:
void Parse(rapidxml::xml_node<> *node)
{
for (rapidxml::xml_attribute<> *attr = node->first_attribute();
attr;
attr = attr->next_attribute())
{
map<std::string, float*>::iterator member = assignmentMap.find(attr->name());
//check for a pre-existing entry
if( member == assignmentMap.end()) continue;
std::stringstream converter;
converter << attr->value();
converter >> *(member->second);
}
}
private:
float x;
float y;
float z;
std::map<std::string, float*> assignmentMap;
};
解决方案
有关与地图的执行,可以使用指针到成员。然后,你将不再需要地图(当你复制它,在地图中的指针仍然指向到原始节点)的深拷贝,它也可以让你在静态整个事情(该图是在每不必要的-instance基础)。
例如:
class Node {
//...
static std::map<std::string, float Node::*> initVarMap();
static float Node::* varFromName(const std::string& name);
};
std::map<std::string, float Node::*> Node::initVarMap()
{
std::map<std::string, float Node::*> varMap;
varMap["x"] = &Node::x;
varMap["y"] = &Node::y;
varMap["z"] = &Node::z;
return varMap;
}
float Node::* Node::varFromName(const std::string& name)
{
static std::map<std::string, float Node::*> varMap = initVarMap();
std::map<std::string, float Node::*>::const_iterator it = varMap.find(name);
return it != varMap.end() ? it->second : NULL;
}
用法:
float Node::* member(varFromName(s));
if (member)
this->*member = xyz;
这是没有任何更多的柔性,虽然。
要支持不同类型的成员,则可能修改上面使用map字符串为“所有支持的成员类型的变体”。
例如左右。的构件设定器访问者应是可重复使用,并以代码的唯一的改变,添加或更改构件的类型,应做到的typedef。
#include <map>
#include <string>
#include <iostream>
#include <boost/variant.hpp>
template <class Obj, class T>
struct MemberSetter: boost::static_visitor<void>
{
Obj* obj;
const T* value;
public:
MemberSetter(Obj* obj, const T* value): obj(obj), value(value) {}
void operator()(T Obj::*member) const
{
obj->*member = *value;
}
template <class U>
void operator()(U Obj::*) const
{
//type mismatch: handle error (or attempt conversion?)
}
};
class Node
{
public:
Node() : i(0), f(0.0f), d(0.0f)
{
}
template <class T>
void set(const std::string& s, T value)
{
std::map<std::string, MemberTypes>::const_iterator it = varMap.find(s);
if (it != varMap.end()) {
boost::apply_visitor(MemberSetter<Node, T>(this, &value), it->second);
} //else handle error
}
void report() const
{
std::cout << i << ' ' << f << ' ' << d << '\n';
}
private:
int i;
float f;
double d;
typedef boost::variant<int Node::*, float Node::*, double Node::*> MemberTypes;
static std::map<std::string, MemberTypes> initVarMap();
static std::map<std::string, MemberTypes> varMap;
};
int main()
{
Node a;
a.set("i", 3);
a.set("d", 4.5);
a.set("f", 1.5f);
a.report();
}
std::map<std::string, Node::MemberTypes> Node::initVarMap()
{
std::map<std::string, Node::MemberTypes> varMap;
varMap["i"] = &Node::i;
varMap["f"] = &Node::f;
varMap["d"] = &Node::d;
return varMap;
}
std::map<std::string, Node::MemberTypes> Node::varMap = Node::initVarMap();
这是自然只是你可以做什么的例子。你可以写一个static_visitor做你想要什么。 E.g存储流和试图提取正确的类型的值对于给定的构件。
其他提示
使用的阵列。此union
另一种方法是让x
,y
和z
是参考(float&
)到数组元素0,1,2 - 或(我的偏好)总是不按名称称呼他们由数
class Node
{
public:
void Parse(rapidxml::xml_node<> *node)
{
std::stringstream converter;
for (rapidxml::xml_attribute<> *attr = node->first_attribute();
attr;
attr = attr->next_attribute())
{
if ( strlen( attr->name() ) != 1
|| *attr->name() < 'x' || *attr->name() > 'z' )
throw rapidxml::parse_error; // or whatever
converter << attr->value() >> ary[ *attr->name() - 'x' ];
}
}
private:
union {
float ary[3]; // this can come in handy elsewhere
struct {
float x;
float y;
float z;
} dim;
};
不隶属于 StackOverflow