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

Same outer structure only one difference between functions

本文关键字:功能 之间 有一个 区别 结构 外部      更新时间:2023-10-16

除了修改的变量之外,我有许多函数做大致相同的事情

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;
}

我想知道的是我可以做些什么来组合代码?我怀疑它会涉及模板,可能是叛徒/函子,但我不确定如何处理它的任何想法?

重新设计 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));
}

你可以使用 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 执行设置而不是返回引用来使其更加灵活。

您可以使用以下特征:

#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。

有点笨拙,但这可能是使用 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));
}

我假设ObjNameCategorystring typedef的,或者可以隐式转换。

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