存储 std::shared_ptr<Foo> 的向量,其中 Foo 是模板类

Posted

技术标签:

【中文标题】存储 std::shared_ptr<Foo> 的向量,其中 Foo 是模板类【英文标题】:Storing vector of std::shared_ptr<Foo> where Foo is a templated class 【发布时间】:2011-04-26 03:28:30 【问题描述】:

我有一个基类,我制作了一个模板,因为我想改变几个函数所需的类型,但我想从这些模板化的基类派生。我想存储这些类的向量。我的想法是在层次结构中的所有内容之上创建一个非模板基类,并使用双重调度来确定类型。我这样做是“正确的方式”吗?

这是场景的代码sn-p:

class FooBase

public:
    virtual void Accept( Visitor &v );
;

template<class T>
class Foo : public FooBase

public:
    virtual void DoThing( const T & );
    virtual void Accept( Visitor &v) = 0;

;

template<>
class Foo<Bar> : public FooBase

public:
    virtual void Accept( Visitor &v )
    
        v.HandleBar( *this );
    
;

template<>
class Foo<Baz> : public FooBase

public:
    virtual void Accept( Visitor &v )
    
        v.HandleBaz( *this );
    
;

//还有很多来自Foo、Foo的派生类

然后在另一个班级

class Visitor

public:
    virtual void HandleBar( Foo<Bar> &f ) = 0;
    virtual void HandleBaz( Foo<Baz> &f ) = 0;
;

class Manager : public Visitor

public:
    void AddFoo( FooBase& f )
    
        a.push_back( f );
    

    void RunAll()
    
        for ( std::vector<std::shared_ptr<FooBase> >::iterator it = a.begin(); it != a.end(); ++it )
        
            (*it)->Accept( *this );
            // do common action that doesn't depend on types
        
    

    virtual void HandleBar( Foo<Bar> &f )
    
         Bar item = GetBarItemFunction(); // not shown
         f.DoThing( item );
    
    virtual void HandleBaz( Foo<Baz> &f )
    
         Baz item = GetBazItemFunction(); // not shown
         f.DoThing( item );
    

private:
    std::vector<std::shared_ptr<FooBase> > a;
;

我只是不知道这是否是“最好”的方法。我可以使用 dynamic_casting,但感觉很脏。那么这是解决这种情况的可靠方法吗?请指教(我希望我没有在示例中留下任何明显的语法错误)

(删除了编辑,这是我的愚蠢错误)

【问题讨论】:

【参考方案1】:

我想你已经差不多了。我会这样写访问者类:

class Visitor

public:
    virtual void HandleFoo( Foo<Bar> &f ) = 0;
    virtual void HandleFoo( Foo<Baz> &f ) = 0;
    //default implementation for unknown Foo types:
    virtual void HandleFoo( FooBase &f ) = 0; 
;

现在您不需要专门化您的模板化 Foo 类,您只需编写以下代码来处理您的应用程序可能需要的所有 T 类。将根据 Foo 中使用的模板类型选择正确的重载 HandleFoo 函数。您仍然需要向访问者类添加方法以避免调用默认行为。

template<class T>
class Foo : public FooBase

public:
    virtual void DoThing( const T & );
    virtual void Accept( Visitor &v) 
        v.HandleFoo( *this );
    ;
;

【讨论】:

哇,我真的在为专业化而苦苦挣扎(正在尝试重用通用代码等)。您的建议正是我所需要的!谢谢! 另一个问题可能是你真的需要这里的访问者模式吗?您可以将函数本身模板化吗? (而不是全班) 但是我怎么知道是打电话给GetBarItemFunction() 还是GetBazItemFunction()?这是代码中 Foo 的不同模板特化分歧的一点...... 我不确定这是否适用于您的情况。这实际上取决于模板类型在概念上是否有助于 Foo 的类型,或者它是否仅适用于某些操作。这显然是愚蠢的,所以我必须做出那个决定。可能有帮助的一件事是考虑 Foo 正在维护的状态——这种状态是否依赖于模板类型?如果是这样,那么我认为这正在实现,如果不是,那么我认为可能会有不同的方法来解决它。

以上是关于存储 std::shared_ptr<Foo> 的向量,其中 Foo 是模板类的主要内容,如果未能解决你的问题,请参考以下文章

std::list<std::shared_ptr>::erase 得到一个 SIGSEGV

C++ 中 make_shared 和普通 shared_ptr 的区别

在单元测试中初始化 unique_ptr

无法将参数 1 从 'std::shared_ptr<ChaseState>' 转换为 'std::shared_ptr<State<Cow>>

使用相同的函数但重载不同的 std::tr1::shared_ptr<T> 和 std::shared_ptr<T>

C++ 复制指针所指向的对象 make_shared shard_ptr