相同的外部结构只有一个功能区别

时间:2015-01-09 13:43:14

标签: c++ c++11

除了修改

之外,我有很多功能大致相同
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但是我不确定如何处理任何想法?

4 个答案:

答案 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));
}

我认为ObjNameCategorytypedef的{​​{1}}或者可以隐式转换。

你仍然需要为每个成员变量添加一个单行函数,如果你想坚持使用硬编码结构,那么在C ++中很难避免。您可能需要考虑将整个结构定义转换为数据,例如从文件加载,打开其他可能性。