2009-10-07 32 views
2

我想知道什麼是更好的使用我的情況,爲什麼。首先我聽說使用RTTI(typeid)是不好的。任何人都能解釋爲什麼如果我確切知道類型在運行時比較它們有什麼問題?此外有什麼例子如何使用boost :: type_of?我發現沒有搜索強大的谷歌:)其他解決方案對我來說是專業化的,但我會neet專注於至少9種新方法。這裏有一個例子我所需要的:C++專業化,type_of或只是typeid

我有這個類

template<typename A, typename B, typename C> 
    class CFoo 
    { 
    void foo() 
    { 
     // Some chunk of code depends on old A type 
    } 

    } 

所以我需要在typeid的,而檢查(什麼是我聽到的是壞的),並讓這些3變現例子,如:

void foo() 
    { 
     if (typeid(A) == typeid(CSomeClass) 
     // Do this chunk of code related to A type 
     else 
     if (typeid(B) == typeid(CSomeClass) 
     // Do this chunk of code related to B type 
     else 
     if (typeid(C) == typeid(CSomeClass) 
     // Do this chunk of code related to C type 
    } 

那麼最好的解決方案是什麼?我不想專門針對所有A,B,C,因爲每種類型都有3種專業化,所以我會得到9種方法或只是這種類型檢查。

回答

6

這是不好的,因爲

  1. A,B和C是在編譯時已知的,但您使用的是運行機制。如果您調用typeid,編譯器將確保將元數據包含到對象文件中。
  2. 如果用實際的代碼替換了「執行與A類型相關的這段代碼」,您將看到在A!= CSomeClass和A有一個代碼的情況下,您將無法編譯代碼不兼容的界面。編譯器仍然試圖翻譯代碼,即使它從未運行。 (請參閱下面的示例)

您通常會將代碼分解爲單獨的函數模板或可以專用的類的靜態成員函數。

壞:

template<typename T> 
void foo(T x) { 
    if (typeid(T)==typeid(int*)) { 
     *x = 23; // instantiation error: an int can't be dereferenced 
    } else { 
     cout << "haha\n"; 
    } 
} 
int main() { 
    foo(42); // T=int --> instantiation error 
} 

更好:

template<typename T> 
void foo(T x) { 
    cout << "haha\n"; 
} 
void foo(int* x) { 
    *x = 23; 
} 
int main() { 
    foo(42); // fine, invokes foo<int>(int) 
} 

乾杯,S

1

我覺得你有你的抽象錯了地方。

我會嘗試重新定義A,B & C的接口,他們需要公開(C++中的抽象基類,純虛方法)。

模板化基本上允許鴨子打字,但它聽起來像CFoo知道太多的關於C類的A B & C類。

typeid的是不好的,因爲:

  1. typeid的可能是昂貴的,醃 二進制文件,進行不應該要求 有多餘的 信息。
  2. 並非所有的編譯器都支持它
  3. 它基本上破壞了類的層次結構。

我推薦的是重構:刪除模板,而是爲A,B & C定義接口,並使CFoo接受這些接口。這將迫使你重構行爲,所以A,B實際上是內聚類型。

4

一般而言,解決方案可以在沒有RTTI的情況下實現。它「可以」表明你沒有正確地認識到軟件的設計。那很不好。有時RTTI 可以雖然是一件好事。

無論如何,在你想做的事情上有些奇怪。難道你不喜歡創建如下設計一些臨時的模板:

template< class T > class TypeWrapper 
{ 
    T t; 
public: 
    void DoSomething() 
    { 
    } 
}; 

然後部分專門爲要如下功能:

template<> class TypeWrapper<CSomeClass> 
{ 
    CSomeClass c; 
public: 
    void DoSomething() 
    { 
    c.DoThatThing(); 
    } 
}; 

然後在類中定義上面你會做一些這樣的如...

模板

class CFoo 
    { 
    TypeWrapper<A> a; 
    TypeWrapper<B> b; 
    TypeWrapper<C> c; 
    void foo() 
    { 
     a.DoSomething(); 
     b.DoSomething(); 
     c.DoSomething(); 
    } 

    } 

這樣,它只是交流如果它正在通過部分專用的模板,則會在「DoSomething」調用中執行某些操作。

2

問題出在您爲每個專業化編寫的代碼塊。

,如果你寫(縱向)

void foo() 
{ 
    if (typeid(A) == typeid(CSomeClass) 
    // Do this chunk of code related to A type 
    else 
    if (typeid(B) == typeid(CSomeClass) 
    // Do this chunk of code related to B type 
    else 
    if (typeid(C) == typeid(CSomeClass) 
    // Do this chunk of code related to C type 
} 

void foo() 
{ 
    A x; 
    foo_(x); 
    B y; 
    foo_(y); 
    C z; 
    foo_(z); 
} 
void foo_(CSomeClass1&) {} 
void foo_(CSomeClass2&) {} 
void foo_(CSomeClass3&) {} 

第二種情況的好處是,當你添加一個類d,你就會得到由提醒不要緊編譯器指出你必須編寫foo_丟失的重載。這可以在第一個變體中被遺忘。

2

恐怕這不會起作用。即使類型不是CSomeClass,那些「代碼塊」也必須是可編譯的。

我不認爲type_of會幫助(如果它是相同的自動和decltype在C++ 0x)。

我認爲你可以將這三個塊抽取爲單獨的函數,併爲CSomeClass重載每個塊。 (編輯:哦有else if's。那麼你可能確實需要大量的過載/專業化。這是什麼代碼?)

編輯2:看起來你的代碼希望做到以下等效,其中int特殊類型:

#include <iostream> 

template <class T> 
bool one() {return false; } 

template <> 
bool one<int>() { std::cout << "one\n"; return true; } 

template <class T> 
bool two() {return false; } 

template <> 
bool two<int>() { std::cout << "two\n"; return true; } 

template <class T> 
bool three() {return false; } 

template <> 
bool three<int>() { std::cout << "three\n"; return true; } 

template <class A, class B, class C> 
struct X 
{ 
    void foo() 
    { 
     one<A>() || two<B>() || three<C>(); 
    } 
}; 

int main() 
{ 
    X<int, double, int>().foo(); //one 
    X<double, int, int>().foo(); //two 
    X<double, double, double>().foo(); //... 
    X<double, double, int>().foo(); //three 
}