2012-01-22 38 views
0

有兩個不相關的結構A和BC++編譯時多態性

template <typename T> 
struct A {}; 

template <typename T> 
struct B {}; 

一個枚舉類型

typedef enum { ma, mb} M; 

和含C類函數模板

class C 
{ 
public: 
    template <typename T> 
    static void f1 (A <T> &a) {} 

    template <typename T> 
    static void f2 (B <T> &b) {} 

    template <typename U> 
    static void algo (U &u, M m) 
    { 
     /*Long algorithm here      
     .... 
     */ 
     if (m == ma) f1(u); 
     else f2(u); 
    } 
}; 

靜態方法ALGO包含一些算法,這相當困難......它將一些值和結果修改爲結構A或B.

我想ALGO與取決於M的值對象A或B運行靜態方法。但怎麼說這句話給我的編譯器:-)

int main() 
{ 
A <double> a; 
C::algo (a, ma); //Error 

} 

Error 1 error C2784: 'void C::f1(A<T>)' : could not deduce template argument for 'A<T>' from 'B<T> 

A]我在想函數指針,但它們與函數模板使用。

B]也許編譯多態性可能有助於

template <typename U, M m> 
static void algo (U &u, M <m>) { ...} //Common for ma 

template <typename U, M m> 
static void algo (U &u, M <mb>) { ...} //Spec. for mb 

但這種解決方案有一個很大的問題:(?爲什麼寫算法兩次)都實現應該不必要囊括了幾乎相同的代碼。

所以我需要函數 algo()處理參數A和B的兩種類型。有沒有更舒適的解決方案?

+7

BTW它是「多態性」。 Polymorfishm有些不同(「Polly,more fish?Hmm?」)。 –

+0

@ Als:我沒有檢查標題:-) – justik

+1

@LightnessRacesinOrbit哦,上帝,我笑了!我的屏幕上現在有牛奶。 –

回答

3

看來你正在使用的枚舉,傳達來自用戶的類型信息。我建議你不要。

在最簡單的情況下,如果f1f2被重命名f,那麼你就可以完全消除if,只是調用它。編譯器會爲你調用適當的重載。

如果您不能或不想重命名功能模板,那麼你可以寫一個輔助模板,會爲你派遣(基本類模板定義,專業化爲AB可分派到相應的靜態函數)

如果枚舉用於別的東西(編譯器解決不了你),你還可以通過它周圍和重寫助手對枚舉調度,而不是參數的類型,你將不得不重新改寫將枚舉值作爲編譯時間常量的代碼(最簡單:將其作爲模板參數傳遞給algo)。在這種情況下,如果你願意的話,你可以編寫函數特化而不是類,因爲它們將是完全專業化的。但請注意,如果您可以避免必須通過它,您將刪除一整套錯誤:傳遞錯誤的枚舉值。

// Remove the enum and rename the functions to be overloads: 
// 
struct C { // If everything is static, you might want to consider using a 
      // namespace rather than a class to bind the functions together... 
      // it will make life easier 

    template <typename T> 
    static void f(A<T> &) { /* implement A version */ } 

    template <typename T> 
    static void f(B<T> &) { /* implement B version */ } 

    template <typename T> // This T is either A<U> or B<U> for a given type U 
    static void algo(T & arg) { 
     // common code 
     f(arg); // compiler will pick up the appropriate template from above 
    } 
}; 

對於其他的替代品,它是比較容易,如果封閉範圍是一個命名空間,但這個想法是相同的(只是可能需要打的語法有點困難:

template <typename T> 
struct dispatcher; 

template <typename T> 
struct dispatcher< A<T> > { 
    static void f(A<T>& arg) { 
     C::f1(arg); 
    } 
}; 
template <typename T> 
struct dispatcher< B<T> > { 
    static void f(B<T>& arg) { 
     C::f2(arg); 
    } 
}; 

template <typename T> 
void C::algo(T & arg) { 
    // common code 
    dispatcher<T>::f(arg); 
} 

再次,讓它與類一起工作可能會有點棘手,因爲它可能需要一些前向聲明,而我手邊沒有編譯器,但草圖應該會帶領您朝着正確的方向前進。

+0

@ David Rodriguez。我可以請你舉個例子:案例B]和C]?非常感謝您的幫助。 – justik

+0

我想我可以打開電腦...在iPad上打字代碼是相當痛苦的... –

+0

@ David Rodriguez:那真的有幫助,再次感謝你...我正在研究第二個例子... – justik

2

普通函數重載就足夠了:

template <typename T> 
static void f1 (A <T> &a) {} 

template <typename T> 
static void f2 (B <T> &b) {} 

template <typename T> 
static void algo (A<T>& u) { 
    f1(u); 
} 

template <typename T> 
static void algo (B<T>& u) { 
    f2(u); 
} 

然後:

A<int> a; 
Foo::algo(a); 

雖然目前還不清楚你站在從這樣的安排,以獲得什麼。

+0

我認爲現在'm'沒用了 – Lol4t0

+0

@ Lol4t0:編輯它。 – Jon

+0

@ Jon:謝謝,但是我需要一個函數來不寫兩次相同的代碼(算法)。 – justik

0

如果你真的需要做的是,在一個功能,您可以使用typetraits:

template<typename T, T Val> 
struct value_type { static const T Value = Val; }; 

struct true_type : public value_type<bool, true>{}; 
struct false_type : public value_type<bool, false>{}; 


template<class T> 
struct isClassA : public false_type{}; 

template<> 
struct isClassA<A> : public true_type{}; 


template < typename T > 
void Algo(T& rcT) 
{ 
    if (true == isClassA<T>::Value) 
    { 
     // Class A algorithm 
    } 
    else 
    { 
     // Other algorithm 
    } 
}; 
+0

@ jisaak:謝謝,但算法可以防止這種情況。所以對於A,B tzpes幾乎都有相同的算法,對於2種類型,沒有兩種不同的算法。 – justik

+0

區分A和B不是條件'M'嗎? –

0

直到m參數的值是未知的因此編譯器必須在專門生成函數時爲if (m == ma)else分支生成代碼。 然後它會抱怨,因爲如果您碰巧打電話給C::algo(a,mb)或類似的東西,它就無法理解他應該怎麼做。

正如喬恩建議,超載應該解決您的情況,請嘗試使用此代碼:

template<typename U> 
static void f12(A<U>&u) { f1(u); } 

template<typename U> 
static void f12(B<U>&u) { f2(u); } 

template<typename U> 
static void algo(U& u, M m) 
{ 
    /* long algorithm here 
     ... 
    */ 
    //use overloading to switch over U type instead of M value 
    f12(u); 
} 

你也可以使用函數指針與模板的功能,只要您指定的模板參數:

template<typename U> 
static void algo(U& u, M m, void(*)(U&) func) 
{ 
    /* ... */ 
    (*func)(u); 
} 

int main() 
{ 
    A <double> a; 
    C::algo (a, ma, &C::f1<double>); 
} 
+0

@ pqnet : 感謝幫助。但我認爲,功能模板的指針是不允許的... – justik

+0

@justik爲什麼你這麼想? – pqnet