【问题标题】:C++ How to avoid repetitive code for variables of different third-party type?C++ 如何避免不同第三方类型变量的重复代码?
【发布时间】:2020-11-10 22:29:40
【问题描述】:

我有一个类管理许多不同但相似类型的相似成员变量。

class Manager {
  Type1 a;
  Type2 b;
  Type3 c;
  void process();
};

虽然类型不同,但它们共享一些功能和属性。至少这让我可以使用一些模板函数以类似的方式处理类成员。

template <typename T>
void process(T& t) {
  // do something with t
}

void Manager::process() {
  process(a);
  process(b);
  process(c);
}

在我的程序中,我还需要提供与成员变量名称相同的字符串。

template <typename T>
void print(T t, std::string name) {
  std::cout << name << ": " << t.msg << std::endl;
}

void Manager::print() {
  print(a, "a");
  print(b, "b");
  print(c, "c");
}

我减少了代码示例来说明我的问题。实际上,在更多的地方,我只需为每个变量复制粘贴整个代码块。时不时会添加一个具有新类型的新成员变量。

我可以使用什么模式来避免这些看似不必要的类似代码重复?

我想到了类似std::map&lt;std::string, ParentType&gt; members; 的东西。我想这将允许我遍历所有成员变量而不是复制粘贴代码,并且我还可以为每个变量存储一个相应的名称字符串。但是,我使用的类型没有公共父类并且是第三方的,即我无法修改Type1/Type2/Type3/...的实现。

我想我真正想要的是只有一个地方可以定义类型和名称,然后能够简单地遍历所有变量以执行类似的处理。

我可以考虑使用预处理器宏来部分解决这个问题,但在现代代码中不是很不鼓励吗?

【问题讨论】:

    标签: c++ design-patterns polymorphism


    【解决方案1】:

    这似乎正是预处理器的用例——删除重复代码和字符串化标识符。如果你不喜欢它,并且你不介意可怕的语法,你可以将Manager 设为一个元组:

    class Manager {
        std::tuple<Type1, Type2, Type3 /* more types can be added ... */> tup;
    }
    

    然后您可以使用std::apply 对每个元素运行一个函数。见Template tuple - calling a function on each element

    void Manager::process() {
        std::apply([](auto ...x){
            std::make_tuple(process(x)...);
        }, this->tup);
    }
    

    如果没有反思,我相信没有更清洁的解决方案。如果没有宏,您的 stringify 打印示例是不可能的。

    【讨论】:

      【解决方案2】:

      您可以为您的类创建模板函数,例如:

      class Manager {
        Type1 a;
        Type2 b;
        Type3 c;
      
        template <typename F>
        void apply(F f)
        {
          f(a); f(b); f(c);
        }
        template <typename F>
        void apply_with_name(F f)
        {
          f("a", a); f("b", b); f("c", c);
        }
      
        void process() { apply([](auto& t){ t.process(); }); }
        void print() { apply_with_name([](const std::string& name, auto& t){ std::cout << name << ": " << t.msg << std::endl; }); }
      };
      

      【讨论】:

        猜你喜欢
        • 2011-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多