[英]Container Object of Templated Class
下面是實現的(非常)精簡代碼。
庫代碼如下:
#pragma once
#include <iostream>
#include <map>
#include <string>
// Necessary as interface and due to QObject Macro.
class Base
{
public:
Base( const std::string& name ) : name_( name )
{
}
virtual ~Base(){}
const std::string& name()
{
return name_;
}
private:
std::string name_;
};
template < typename Derived, typename ObjectType >
class TemplatedBase : public Base
{
public:
TemplatedBase( const std::string& name ) : Base( name )
{
}
ObjectType object()
{
return object_;
}
ObjectType object_;
};
class DerivedA : public TemplatedBase< DerivedA, int >
{
public:
DerivedA( const std::string& name ) : TemplatedBase< DerivedA, int >( name )
{
}
};
class DerivedB : public TemplatedBase< DerivedB, float >
{
public:
DerivedB( const std::string& name ) : TemplatedBase< DerivedB, float >( name )
{
}
};
class Container
{
public:
template < typename T >
void addToMap( T& map_object )
{
const std::string name = map_object.name();
// ASSERT( map_.find( name ) == map_.end() );
map_.emplace( std::make_pair( name, &map_object ) );
}
template < typename T >
auto getObject( std::string name ) -> decltype( ( ( T* )nullptr )->object() )
{
auto search = map_.find( name );
// How can this dynamic_cast be avoided?
T* ptr = dynamic_cast< T* >( search->second );
// ASSERT( ptr == nullptr );
return ptr->object();
}
std::map< std::string, Base* > map_;
};
使用以下示例:
int main( int argc, char* argv[] )
{
Container container;
DerivedA a( "Name_A" );
DerivedB b( "Name_B" );
container.addToMap( a );
container.addToMap( b );
// How can I avoid to specify the type in the map as template?
auto object_a = container.getObject< DerivedA >( "Name_A" );
auto object_b = container.getObject< DerivedB >( "Name_B" );
}
該代碼的一些解釋:
Q_OBJECT
宏以及接口都需要非模板類。 雖然代碼本身可以正常工作,但我正在尋找一種不同的設計,該設計使得在讀出期間不需要dynamic_cast和類型規范。
我嘗試了幾種類型的類型擦除(boost :: type_erasure,boost :: variant)和不同的容器類型。 但是,我總是遇到object()
函數的不同返回類型的問題。
如果要返回Base
以外的特定類型,則無法避免將類型名稱放在此處:
auto object_a = container.getObject< DerivedA >( "Name_A" );
編譯器無法知道在編譯時返回什么,因為直到運行時才知道該值。
至於您對演員表的重新詮釋,您不喜歡它是正確的。 這需要是dynamic_cast,或者您必須構建其他方式來告訴您的對象在運行時進入系統的類型。 另外,您可能意味着static_cast
不重新解釋static_cast
。 但是,如果您不完全知道每次查詢都將正確的對應類型指定為與存儲對象的實際運行時類型匹配的模板參數,則static_cast
也不正確。
現在,如果打錯電話,系統將導致未定義的行為。 您的代碼“運行正常”,因為您沒有使用不兼容的模板類型調用getObject,但是一旦這樣做,您的程序就可能無法正常運行。
讓我們考慮一下您到底在做什么:
const
。 因此, 此處要使用的正確轉換是static_cast
。
但是,如果用戶不小心用不匹配的類型調用container.getObject
,這將中斷(=導致未定義的行為)。 因此,您應該按照xaxxon的answer中的說明檢查轉換結果的正確性。
不,沒有避免避免在轉換中指定目標類型的方法。 您必須為對象指定靜態類型才能使用它,因為ptr->object()
的結果不會被類型擦除。 甚至boost::variant
要求用戶在實際要訪問存儲的對象時(例如,在訪問者的簽名中)指定靜態類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.