将模板化对象存储为成员对象

Phi*_*ipp 10 c++ performance

假设你有这样的代码:

struct Manager
{
  template <class T> 
  void doSomething(T const& t)
  {
    Worker<T> worker;
    worker.work(t);
  }
};
Run Code Online (Sandbox Code Playgroud)

"管理器"对象创建一次,并使用一些不同类型"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);
}
Run Code Online (Sandbox Code Playgroud)

现在分析表明,构建一个Worker<T>是一个耗时的操作,应该避免构造它N次(内doSomething<T>).出于线程安全的原因,可以使用一个Worker<int>,一个Worker<char>Worker<float>每个"管理器",但不是一个Worker<int>适用于所有管理器.所以通常我会把"worker"变成一个成员变量.但是我怎么能在上面的代码中这样做呢?(我事先不知道会使用哪个"T").

我找到了一个使用std :: map的解决方案,但它不是完全类型安全的,当然也不是很优雅.在Worker<T>没有虚拟方法的情况下,你能建议一种类型安全的方式而不是每个"T" 构建一次吗?

(请注意,Worker不是从任何模板参数的免费基类派生的).

谢谢你的解决方案!

Mar*_*utz 7

你可以使用类似这样的东西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;
}
Run Code Online (Sandbox Code Playgroud)

这是类型安全的,因为我们将其type_info用作地图的索引.此外,工作人员被正确删除,即使他们在shared_ptr<void>s中,因为删除器是从原始shared_ptr<Worker<T> >s 复制的,并且那个人调用了正确的构造函数.它也不使用虚函数,尽管所有类型擦除(并且这是一个)在某处使用类似虚函数的东西.在这里,它在shared_ptr.

将与模板无关的代码findWorker分解为非模板函数以减少代码膨胀是留给读者的练习:)

感谢所有评论员指出type_info直接使用密钥的错误.

  • @mmutz:type_info不可分配.你试过编译吗? (3认同)
  • @Emile:当他们的类型被删除时,他们仍然有正确的删除器. (2认同)