2013-03-03 41 views
0

我在頭文件中定義了以下模板函數。如何直接從通過模板函數的類型檢查類型而不是從變量?

template <class T> T* spawnEnemy(SpawnDirection dir); 

我的目的是創建一個接受敵人類型作爲模板參數的一般產卵功能,從函數返回衍生的對象。

以下是不正確實現,但我用它來表達我想實現的目標。

template <class T> T* ObjectSpawner::spawnEnemy(SpawnDirection dir) 
{ 
    if(_enemiesPool->isAnyFreeObjects()) 
    { 
     T* enemy = NULL; 
     if(typeof(T*) == Zombie01) // This line is INCORRECT 
      enemy = dynamic_cast<T*>(_enemiesPool->popFreeObjectAndAddToActiveListForType(ZOMBIE)); 
     else if ... 

     return enemy; 
    } 
    else 
     return NULL; 
} 

這就是我需要能夠做到從類型Ť檢查,這樣我就可以適當地調用函數

popFreeObjectAndAddToActiveListForType(int type) 

與正確的值作爲其輸入。

那麼如何在模板函數中這樣的情況下進行類型檢查呢?

編輯: 從stephen linnvoigt得到了一個建議後,我看到這個設計有一個缺陷,但這是因爲我已經從我已經完成了它。更容易的是讓函數具有另一個類型參數並且不涉及模板,但需要稍後轉換爲特定類型。無論如何,瞭解這種情況的解決方案是很好的。

+2

'T *'已經是一個特定的類型,一旦你實例化模板,所以我不清楚爲什麼你需要檢查它。如果你想'T *'映射到'int type'參數的特定常量,那麼你需要某種類型的特徵。 – 2013-03-03 21:54:09

+1

不能用類型參數調用你的函數嗎?像「模板無效popFreeObjectAndAddToActiveListForType()」?爲什麼要有類型的int? – nvoigt 2013-03-03 21:57:19

+1

@haxpor什麼nvoight說 – 2013-03-03 22:00:13

回答

1

認爲你想這樣的事情(使用類型特徵):

以下部分代碼必須放在類部分之外。

template <typename T> 
struct EnemyTraits { }; 

template <> 
struct EnemyTraits<Zombie01> { static const int pop_type = ZOMBIE; }; 

template <> 
struct EnemyTraits<Vampire01> { static const int pop_type = VAMPIRE; }; 

應按照this中的建議在頭文件中定義以下函數。

template <typename T> T* ObjectSpawner::spawnEnemy(SpawnDirection dir) 
{ 
    if(_enemiesPool->isAnyFreeObjects()) 
    { 
     const int pop_type = EnemyTraits<T>::pop_type; 
     return dynamic_cast<T*>(_enemiesPool->popFreeObjectAndAddToActiveListForType(pop_type)); 
    } 
    else 
     return NULL; 
} 
+0

謝謝,我得到了一些關於C++和這個有趣的類型特徵的有用花絮。 但是,我得到了一個鏈接器錯誤,指出「架構armv7的未定義符號: 」Zombie01 * ObjectSpawner :: spawnEnemy (ObjectSpawner :: SpawnDirection)「,引用自:...」。我相信這是關於在哪裏聲明或自己的語法。 我看了一下[boost](http://www.boost.org/doc/libs/1_37_0/boost/type_traits/detail/is_mem_fun_pointer_impl.hpp),儘管我們不在這裏做什麼,但是我找不到任何錯誤的步驟。 – haxpor 2013-03-04 04:53:37

+0

我在頭文件中定義了泛型模板,在實現文件中定義了專門化模板,因爲如果我把它放在頭文件中,我得到了一個編譯錯誤。我也看看這個[link](http://accu.org/index.php/journals/442#boost),但目前爲止還沒有工作。 – haxpor 2013-03-04 04:56:30

+0

你把所有上面的頭文件? [(有用的信息)](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file)...你也可以做明確的實例化替代方案,但這是少一些標準 – 2013-03-04 04:56:42

1

一種可能性是使用dynamic_cast,如果T是基類的Zombie01

T *enemy = dynamic_cast<Zombie01*>(x); 
if (!enemy) 
{ 
    // x can not cast to Zombie01 
    // do something else 
} 

但是,建議儘量減少dynamic_cast

使用另一個想法是使用std::is_same

如果T和U的名稱與具有相同常數的同類型 等級提供的成員常量值等於true。 否則值爲false。

不過,我試圖用斯科特邁爾斯的提示,從有效的C++:

「無論何時你發現自己編寫形式的代碼」如果對象是類型T1的 ,然後做一些事情,但如果它的類型T2的,然後做 別的事情,」摑自己

+1

我自己打了一個。 – haxpor 2013-03-03 22:17:49

+0

我儘量避免使用dynamic_cast,它需要太多if-if。此外,我現在沒有使用C++ 11,所以我找不到is_same,但感謝您向我介紹它。 – haxpor 2013-03-03 22:24:05

+0

@ M.M。 fyi,如果'T'實際上是'Zombie01'的基類並不重要,dynamic_cast會[cross-cast](http://stackoverflow.com/questions/5321664/checking-whether-a-crosscast - 可能工作)任何兩個多態指針。 – 2013-03-03 22:34:13

相關問題