使C ++成员函数更优雅的方法是根据模板参数更改不同的成员变量?

时间:2010-06-01 20:50:16

标签: c++ templates dry

今天,我编写了一些代码,需要根据模板参数的类型向不同的容器变量添加元素。我通过编写一个专门用于自己的模板参数的朋友助手类来解决它,该模板参数具有原始类的成员变量。它为我节省了几百行重复自己而没有增加太多复杂性。然而,它看起来像kludgey。我想知道是否有更好,更优雅的方式。

以下代码是一个极为简化的示例,说明了问题和我的解决方案。它用g ++编译。

#include <vector>
#include <algorithm>
#include <iostream>

namespace myNS{

  template<class Elt>
  struct Container{
    std::vector<Elt> contents;
    template<class Iter>
    void set(Iter begin, Iter end){
      contents.erase(contents.begin(), contents.end());
      std::copy(begin, end, back_inserter(contents));
    }
  };


  struct User;

  namespace WkNS{
    template<class Elt>
    struct Worker{
      User& u;

      Worker(User& u):u(u){}

      template<class Iter>
      void set(Iter begin, Iter end);
    };
  };

  struct F{ int x; explicit F(int x):x(x){} };
  struct G{ double x; explicit G(double x):x(x){} };

  struct User{
    Container<F> a;
    Container<G> b;

    template<class Elt>
    void doIt(Elt x, Elt y){
      std::vector<Elt> v; v.push_back(x); v.push_back(y);
      Worker<Elt>(*this).set(v.begin(), v.end());
    }

  };


  namespace WkNS{
    template<class Elt> template<class Iter>
    void Worker<Elt>::set(Iter begin, Iter end){
      std::cout << "Set a." << std::endl;
      u.a.set(begin, end);
    }

    template<> template<class Iter>
    void Worker<G>::set(Iter begin, Iter end){
      std::cout << "Set b." << std::endl;
      u.b.set(begin, end);
    }
  };

};

int main(){
  using myNS::F; using myNS::G;
  myNS::User u;
  u.doIt(F(1),F(2));
  u.doIt(G(3),G(4));
}

User是我写的课程。

Worker是我的帮助班。我在它自己的命名空间中拥有它,因为我不希望它在myNS之外造成麻烦。

Container是一个容器类,其定义我不想修改,但User在其实例变量中使用。

doIt<F>应该修改一个。 doIt<G>应修改b。

FG可以进行有限修改,如果这样可以产生更优雅的解决方案。 (作为一个这样的修改的一个例子,在实际应用程序中F的构造函数接受一个伪参数,使其看起来像G的构造函数,并使我免于重复自己。)

在实际代码中,WorkerUser的朋友,成员变量是私有的。为了使示例更简单,我将所有内容都公之于众。但是,需要公开的解决方案确实无法回答我的问题。

鉴于所有这些警告,是否有更好的方法来编写User::doIt

1 个答案:

答案 0 :(得分:1)

在阅读了Emile Cormier的评论之后,我想到了一种方法,既可以不重复自己也可以消除Worker类:为doIt制作两个简单的非模板F函数和G并且每次调用第三个模板doIt函数,并将要更改的变量作为参数传递。这是修改后的代码。

#include <vector>
#include <algorithm>
#include <iostream>

namespace myNS{

  template<class Elt>
  struct Container{
    std::vector<Elt> contents;
    template<class Iter>
    void set(Iter begin, Iter end){
      contents.erase(contents.begin(), contents.end());
      std::copy(begin, end, back_inserter(contents));
    }
  };

  struct F{ int x; explicit F(int x):x(x){} };
  struct G{ double x; explicit G(double x):x(x){} };

  struct User{
    Container<F> a;
    Container<G> b;

    template<class Elt>
    void doIt(Elt x, Elt y, Container<Elt>& cont, const char*name){
      std::vector<Elt> v; v.push_back(x); v.push_back(y);
      cont.set(v.begin(), v.end());
      std::cout << "Set " << name << std::endl;
    }

    void doIt(F x, F y){ doIt(x,y,a,"a"); }

    void doIt(G x, G y){ doIt(x,y,b,"b"); }

  };

}

int main(){
  using myNS::F; using myNS::G;
  myNS::User u;
  u.doIt(F(1),F(2));
  u.doIt(G(3),G(4));
}