2010-06-01 156 views
2

今天,我写了一些代码,需要根据模板参数的类型将元素添加到不同的容器变量。我通过编写一个专门用于自己的模板参数的朋友帮助类来解决这个问题,该参数有一个原始类的成员变量。它为我节省了几百行重复自己的工作,而不会增加很多复杂性。然而,它似乎是kludgey。我想知道是否有更好,更优雅的方式。更好的方法来使C++成员函数根据模板参数改变不同的成员变量?

下面的代码是一个非常简化的例子,说明了问题和我的解决方案。它用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的构造和保存箱从重复自己。)

在实际代码,Worker是一个User的朋友和成员变量是私人的。为了让这个例子更容易写,我公开了一切。然而,要求事物公开的解决方案并不能回答我的问题。

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

+0

为什么不只是有一个非模板'User :: doIt'成员函数为'F'和'G'重载? – 2010-06-01 23:35:23

+0

真正的'User :: doIt'是复杂的(它对多维插值例程进行预计算)并且对a和b几乎完成相同的事情,主要区别在于使用F和G对象的适当成员函数。该模板避免了复制/粘贴重复代码。 – Eponymous 2010-06-02 00:37:51

回答

1

阅读埃米尔·科米尔的评论后,我想了一个办法,无论是从重复自己,也消除了Worker类保持:做两个微不足道的非模板doIt功能FG,让每个调用第三个模板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)); 
}