下面是(非常)剥离的实现代码。
库代码如下:
#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()
函数的不同返回类型的问题。
答案 0 :(得分:2)
如果您想要返回Base
以外的特定类型,则无法避免在此处输入类型名称:
auto object_a = container.getObject< DerivedA >( "Name_A" );
编译器无法知道在编译时返回什么,因为直到运行时才知道该值。
至于你的重新演绎,你是不是喜欢它。这需要是dynamic_cast,或者您必须构建一些其他方法来告诉您的对象在运行时对系统的类型。此外,您可能意味着static_cast
没有重新解释演员表。但是,如果您不完全知道每个查找都将指定正确的对应类型作为与存储对象的实际运行时类型匹配的模板参数,则static_cast
也不正确。
现在,如果您拨打了错误电话,系统将导致未定义的行为。你的代码是&#34;工作正常&#34;因为您没有使用不兼容的模板类型调用getObject,但是一旦执行,您的程序可能无法正常工作。
答案 1 :(得分:1)
让我们考虑一下你在这里做了什么:
const
- ness。因此,此处使用的正确广播<{3}} 。
但是,如果用户意外调用类型不匹配的container.getObject
,则会中断(导致未定义的行为)。因此,应检查投射结果的正确性,如static_cast
中所述。
不,没有办法避免在演员表中指定目标类型。您必须为对象指定静态类型才能使用它,因为ptr->object()
的结果未被类型擦除。即使boost::variant
要求用户在实际想要访问存储对象时(例如在访问者的签名中)指定静态类型。