2011-06-15 93 views
16

我想定義一個像任務農業遞歸結構。在這裏,我嘗試了兩個操作數遞歸地可以爲任意數量的操作數工作,因爲它可以嵌套自己。C++自動檢測模板參數?

template <typename T1, typename T2> 
class Farm 
{ 
    private: 
    T1 *task1; 
    T2 *task2; 
    public: 
    // save them so that I can use them when invoking call operator 
    Farm(T1 *_t1, T2 *_t2): task1(_t1), task2(_t2) { } 

    void operator()() 
    { 
     // invoke call operator, meaning a farm could be a task (arbitrary nesting) 
     (*task1)(); 
     (*task2)(); 
    } 
}; 
int main() 
{ 
    ... create two pointer(A *a, B *b...) 
    Farm(a,b); // error: missing template arguments before ‘(’ token 

    Farm<A, B>(a,b); // in this works, it works 
} 

問題是自動檢測模板參數在這種情況下不起作用。我在做什麼錯了,我怎麼能通過gcc編譯器實現這個模板參數的隱式檢測。

謝謝!

回答

16

類/構造函數不像函數那樣自動檢測類型。你需要編寫一個包裝函數來創建你的類。

這樣做如下,並稱爲Object Generator模式。 (感謝@Itjax!)

template <typename T1, typename T2> 
Farm<T1, T2> makeFarm(T1* a, T2* b) { 
     return Farm<T1,T2>(a,b); 
} 

// silly example 
Farm<T1,T2> farm = makeFarm(a,b); 

// better example 
template<typename T> 
void plow(T& farm) { farm.applyTractor(...); } 

void blah() { 
    plow(makeFarm(b,a)) 
} 

使用lambda /綁定/的foreach和類似零件時,當你想創建一些參數的模板類的臨時對象,避免指定其類型此模式出現不少,通常將它發送到另一個模板函數(std::for_each)或多態對象(std::function)。

注意:生成器函數通常是內聯的,並且使用copy-elision優化可能根本沒有在代碼中調用的複製構造函數。如果你不能複製你的對象,makeFarm()應該返回一個智能指針(std::unique_ptr在現代C++中是首選)。

+3

沒錯。這就是所謂的Object Generator成語:http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Object_Generator – ltjax 2011-06-15 14:49:25

+0

非常感謝您的回答!但是,你能告訴我如何擴展這個_Farm_來爲任意模板參數(使用C++ 0x可變參數模板和可能的元組)。我已經讀了很多,並試圖做到這一點,但不能提出解決方案。 – usman 2011-06-15 15:16:42

+0

@ user600029:這是一個不同的問題。請搜索(或發佈一個新問題)。就個人而言,我還沒有使用C++ 0x足以幫助你,但我相信在這裏有很多人知道如何正確地做到這一點。 – Macke 2011-06-16 07:18:24

4

通常的解決方法是提供一個模板函數,它返回實際的實現。標準的C++庫使用了很多,例如與std :: make_pair。

例子:

template<typename T> 
struct foo_t { 
    ... 
}; 

template<typename T> 
foo_t<T> foo(T const &f) { 
    return foo_t<T>(f); 
} 

這工作,因爲對於功能的編譯器允許從參數列表推斷typenames。

1

你可以添加一個基類的類農場:

class FarmBase 
{ 
    public: 
    virtual ~FarmBase(){} 

    virtual void operator()() = 0; 
}; 


template <typename T1, typename T2> 
class Farm : public FramBase 
{ 
    private: 
    T1 *task1; 
    T2 *task2; 
    public: 
    // save them so that I can use them when invoking call operator 
    Farm(T1 *_t1, T2 *_t2): task1(_t1), task2(_t2) { } 
    virtual ~Farm(){} 

    virtual void operator()() 
    { 
     // invoke call operator, meaning a farm could be a task (arbitrary nesting) 
     (*task1)(); 
     (*task2)(); 
    } 
}; 
template< typename A, typename B > 
FarmBase* Create(A *a, B *b) 
{ 
    return new Farm< A, B >(a, b); 
} 

然後主要的樣子:

int main() 
{ 
    //... create two pointer(A *a, B *b...) 

    FarmBase *fobj = CreateFarm(a, b); 
} 
+0

如何自動幫助C++ 0x?只是好奇。 – Macke 2011-06-15 14:54:09

+1

@Macke刪除了廢話 – 2011-06-15 15:10:37