2010-06-01 148 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)); 
}