除了修改
之外,我有很多功能大致相同struct example
{
std::string name;
std::string category;
};
using ObjName = std::string;
using Value = std::string;
bool updateName(const ObjName &name, const Value& value) ...
bool updateCategory(const ObjName &name,const Value& value)
{
// boost optional pointing to struct reference
auto obj = findOjb(name);
if (obj)
{
obj.get().category = value; // variable name changes
return true;
}
return false;
}
我想知道的是我可以做些什么来组合代码? 我怀疑它会涉及模板可能是traites / functors但是我不确定如何处理任何想法?
答案 0 :(得分:6)
重做Daerst的代码,删除那个糟糕的offsetof
,转而使用指向成员的指针...
struct example
{
std::string name;
std::string category;
};
bool updateVariable(const ObjName &name, std::string example::*member, std::string const &value)
{
// your code ...
// Access
rule.get().*member = value
// rest of your code
}
bool updateName(const ObjName &oldname, const ObjName& newName)
{
return updateVariable(name, &example::name, newName));
}
bool updateCategory(const ObjName &name, Category &cat)
{
return updateVariable(name, &example::category, cat));
}
答案 1 :(得分:4)
你可以使用lambdas:
template <typename Accessor>
bool updateVariable(const ObjName& name, const Value& value, Accessor access) {
auto obj = findObj(name);
if (obj)
{
access(obj.get()) = value;
return true;
}
return false;
}
bool updateCategory(const ObjName& name, const Value& value) {
return updateVariable(name, value,
[](Example& e) -> Value& { return e.category; });
}
这比指针到成员解决方案更灵活。通过让lambda进行设置而不是返回引用,可以使其更加灵活。
答案 2 :(得分:2)
您可以使用以下特征:
#include <string>
#include <assert.h>
struct example
{
std::string name;
int category;
};
struct nameDesc
{
typedef std::string valuetype;
static void set(example& obj, const valuetype& val)
{
obj.name = val;
}
};
struct categoryDesc
{
typedef int valuetype;
static void set(example& obj, const valuetype& val)
{
obj.category = val;
}
};
example test; // just for testing...
example& findObj(const std::string &name)
{
// just for testing...
return test;
}
template <typename V>
bool update(const std::string &objName, const typename V::valuetype& value)
{
example& obj = findObj(objName);
V::set(obj, value);
return true;
}
bool updateName(const std::string &objName, const std::string& value) { return update<nameDesc>(objName, value); }
bool updateCategory(const std::string &objName, int value) { return update<categoryDesc>(objName, value); }
int main()
{
update<nameDesc>("objname", "asdf");
update<categoryDesc>("objname", 1234);
assert(test.name == "asdf");
assert(test.category == 1234);
updateName("objname", "qwer");
updateCategory("objname", 7890);
assert(test.name == "qwer");
assert(test.category == 7890);
return 0;
}
我鼓励你尽可能看看boost :: spirit / BOOST_FUSION_ADAPT_STRUCT。
答案 3 :(得分:-1)
有点hacky,但这可能是使用offsetof
的解决方案(未经测试的代码):
struct example
{
std::string name;
std::string category;
};
bool updateVariable(const size_t offset, std::string value)
{
// your code ...
// ASSIGNMENT: get address, apply offset and assign value
*(&rule.get() + offset) = cat;
// rest of your code
}
bool updateName(const ObjName &oldname, const ObjName& newName)
{
return updateVariable(offsetof(struct example, name), newName));
}
bool updateCategory(const ObjName &name, Category &cat)
{
return updateVariable(offsetof(struct example, category), cat));
}
我认为ObjName
和Category
是typedef
的{{1}}或者可以隐式转换。
你仍然需要为每个成员变量添加一个单行函数,如果你想坚持使用硬编码结构,那么在C ++中很难避免。您可能需要考虑将整个结构定义转换为数据,例如从文件加载,打开其他可能性。