假设你有一些这样的代码:
struct Manager { template <class T> void doSomething(T const& t) { Worker<T> worker; worker.work(t); } };
一个“管理器”对象被创建一次,并使用一些不同类型“T”进行调用,但每个类型T被调用多次.这可能是一个简化的形式
Manager manager; const int N = 1000; for (int i=0;i<N;i++) { manager.doSomething<int>(3); manager.doSomething<char>('x'); manager.doSomething<float>(3.14); }
现在,剖析表明,构建一个“工人”是一个耗时的操作,应该避免构造它N次(在doSomething< T>)内.为了线程安全的原因,可以有一个Worker< int>,一个Worker< char>和< float>每个“经理”,但不是一个工作者< int>为所有经理.所以通常我会使“worker”成员变量.但是我该如何在上面的代码中做到这一点? (我事先不知道会使用“T”).
我已经找到了一个使用std :: map的解决方案,但它并不完全是类型安全的,当然不太优雅.你可以建议一种类型安全的方式,而不需要构建“工作人员”没有虚拟方法,每“T”多一次?
(请注意,Worker不是源自任何模板参数的免费基类).
谢谢任何解决方案!
解决方法
您可以使用类似std :: map< std :: type_info,shared_ptr< void> >喜欢这个:
#include <map> #include <typeinfo> #include <utility> #include <functional> #include <boost/shared_ptr.hpp> using namespace std; using namespace boost; // exposition only: template <typename T> struct Worker { void work( const T & ) {} }; // wrapper around type_info (could use reference_wrapper,// but the code would be similar) to make it usable as a map<> key: struct TypeInfo { const type_info & ti; /*implicit*/ TypeInfo( const type_info & ti ) : ti( ti ) {} }; // make it LessComparable (could spcialise std::less,too): bool operator<( const TypeInfo & lhs,const TypeInfo & rhs ) { return lhs.ti.before( rhs.ti ); } struct Manager { map<TypeInfo,shared_ptr<void> > m_workers; template <class T> Worker<T> * findWorker() { const map<TypeInfo,shared_ptr<void> >::const_iterator it = m_workers.find( typeid(T) ); if ( it == m_workers.end() ) { const shared_ptr< Worker<T> > nworker( new Worker<T> ); m_workers[typeid(T)] = nworker; return nworker.get(); } else { return static_cast<Worker<T>*>( it->second.get() ); } } template <typename T> void doSomething( const T & t ) { findWorker<T>()->work( t ); } }; int main() { Manager m; m.doSomething( 1 ); m.doSomething( 1. ); return 0; }
这是类型安全的,因为我们使用type_info作为地图中的索引.而且,即使它们在shared_ptr< void>中,工作者也被正确删除,因为删除者是从原始的shared_ptr< Worker< T>并且那个调用正确的构造函数.它也不使用虚拟函数,虽然所有类型的擦除(和这是一个)在某处使用类似虚拟函数.这里是shared_ptr.