2016-04-11 100 views
0

我怎樣才能讓在C++中是這樣的:返回類型T的C++

C#代碼:

public T GetComponent<T>() where T : Component 
     { 
     foreach (var c in Components) 
     { 
      if (c is T) return (T)c; 
     } 
     foreach (var c in componentsToAdd) 
     { 
      if (c is T) return (T)c; 
     } 
     return null; 
    } 
+1

@ user4581301不是特別有用,他是在追求更具體的東西之後。 –

+0

你的問題到底是什麼?我有點不確定。你關注'T'的類型約束還是你想了解模板(C#泛型)?事實上,這個問題很難理解。 – callyalater

+0

難道這不是通過簡單地使用[std :: find](http://en.cppreference.com/w/cpp/algorithm/find)來完成的嗎?如果不是,你可以提供一些關於你想要做什麼的信息,以及包含「組件」的集合嗎? –

回答

1

返回一個泛型類型 'T' 是容易的,但有沒有(漂亮)等效到C#限制(但請參閱callyalater的評論):

public: 
    template<typename T> // where T : Component - no equivalent 
    T GetComponent() 
    { 
     for (auto c : Components) 
     { 
      if (dynamic_cast<T>(c) != nullptr) 
      { 
       return static_cast<T>(c); 
      } 
     } 
     for (auto c : componentsToAdd) 
     { 
      if (dynamic_cast<T>(c) != nullptr) 
      { 
       return static_cast<T>(c); 
      } 
     } 
     return nullptr; 
    } 
+1

您可以模擬類似這樣的約束:'#define U_EXTENDS_V(U,V)\t template :: value> :: type>'或 ' #define U_SUPER_V(U,V)\t \t template :: value> :: type>',但它確實很醜。 – callyalater

+0

@callyalater:有趣的解決方法! –

+0

我不得不在工作中強制類型約束,並且經過大量研究發現這種方法可行(並且像Java的類型約束),但實際上非常醜陋,而且每次我不得不使用它時,我都討厭自己。 – callyalater

1

你要求的其實很複雜。 C++沒有本地類型反射,因此無法在運行時(很容易)確定類型是否是另一類型的子類。這種實時類型檢查必須手動完成。

這會不會是一個完整的解決方案,但它應該讓你的存在方式的一部分:


這是我自己的發動機類似的一段代碼。這裏的重要一點是函數聲明上方的template

map<type_index, shared_ptr<GameComponent>> type_components; 

template<typename T = enable_if<is_base_of<GameComponent, T>::value>::type> 
shared_ptr<T> get_component() const 
{ 
    static const std::type_index TYPE_INDEX = typeid(T); 

    auto component = type_components.find(TYPE_INDEX); 

    if (component == type_components.end()) 
    { 
     return nullptr; 
    } 

    return static_pointer_cast<T, GameComponent>(*component); 
} 

template<typename T = enable_if<is_base_of<GameComponent, T>::value>::type> 
shared_ptr<T> add_component() 
{ 
    static const type_index TYPE_INDEX = typeid(T); 

    auto component = make_shared<T>(); 

    type_components.insert(make_pair(TYPE_INDEX, component)); 

    return component; 
} 

然後調用它像這樣:

get_component<DerivedGameComponent>(); 

如果傳入的類型不是GameComponent基地,編譯器將拋出一個錯誤。

與C#相比,系統的侷限性相當明顯。首先也是最明顯的,它對類型層次結構一無所知。例如:

struct A : GameComponent { }; 
struct B : A { }; 

add_component<B>(); 
get_component<A>(); 

get_component調用將返回null,因爲它不知道BA一個子類。爲了在我自己的項目中解決這個問題,我所有的遊戲組件和對象都嵌入到Python中,並且我將它用於爲我進行類型和層次結構檢查。

+0

我之前已經完成了這種類型約束(請參閱上面的@DaveDoknjas答案中的我的評論),但是我把它放到宏定義中,因爲它太長了,而且很難理解。這也令人討厭,因爲編譯器錯誤在抱怨時不會給你一個非常有用的錯誤信息,而且在你的代碼中很難追蹤。 – callyalater