【问题标题】:Class template with constructor forwarding具有构造函数转发的类模板
【发布时间】:2015-02-19 22:41:48
【问题描述】:

我想知道实现以下内容的最佳方式是什么。

我有许多派生自抽象类BaseClass 的类。我想创建一个新类ParallelBaseClass,它基本上执行BaseClass 的所有子级的并行化。

我想到的设计是这样的:

template <class D>
class ParallelBaseClass
{
  private:
     std::vector<D> _classes;

   public:

   ParallelBaseClass(int threads, constructor_args)
   {
       for(int i = 0; i < threads; i++)
         _classes.push_back(D(constructor_args));
   }
}

但是,我不知道这是最好的设计。我有两个问题:

  1. 确保模板类型是BaseClass 的后代
  2. 如上所示转发构造函数参数。

非常感谢任何指导。

谢谢!

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    如果这些类都具有执行某些操作的函数(例如execute),并且ParallelBaseClass 应该在不同线程中同时在多个对象上调用它,这可能是一种设计:

    #include <utility> // for std::forward
    
    class Base {
    public:
        virtual void execute() = 0;
    }
    
    
    class Example : public Base {
    public:
        void execute() override { .... }
    }
    
    template<typename D>
    class Parallel : public Base {
    private:
        std::vector<D> objects_; // Called objects, since classes refers to the type and not instances of it
    public:
        template<typename... Args>
        explicit ParallelBase(int threads, Args&&... args) {
            for(int i = 0; i < threads; ++i)
                objects_.emplace_back( args... );
                // not using std::forward<Args>(args)... here:
                // need to make (multiple) copies instead of moving
        }
    
        void execute() override {
            for(D& obj : objects_)
                //create thread and run objects_[i].execute()
        }
    }
    

    构造函数是一个可变参数模板函数,它将参数转发给D 的构造函数。 std::forward 转发而不是作为右值引用或尽可能作为引用。 ... 扩展了模板参数包。 explicit 确保不能使用零 args 参数的构造将 int 隐式转换为 ParallelBase

    这里的Base 是抽象的和多态的。这将对应于组合设计模式。 Parallel(这里不是基类)对应于 D 功能的并行化,并具有 execute 实现本身。

    更新 固定移动构造。

    【讨论】:

    • 谢谢!这正是我想要的。
    • 在循环中使用std::forward 可能会产生(用户)意想不到的结果(想想std::unique_ptr&lt;T&gt;&amp;&amp;)。
    【解决方案2】:

    以下可能会有所帮助:

    template <class Base>
    class ParallelBaseClass
    {
    private:
         std::vector<std::unique_ptr<Base>> classes;
    
     public:
    
        template<typename Derived, typename ... Ts>
        void Add(Ts&&...args)
        {
            classes.push_back(std::make_unique<Derived>(std::forward<Ts>(args)...));
        }
    
    };
    

    用法:

    struct B { virtual ~B() = default; };
    struct D : B { D(int) {} };
    
    ParallelBaseClass<B> p;
    
    p.Add<D>(42);
    

    【讨论】:

    • 感谢您的帮助,两个答案都很棒。不过我确实有一个问题。与存储对象本身的向量相比,将派生类存储在指针向量中是否有任何明显的优势/劣势?
    • @pragmatist1:如果您使用 Base 对象的 vector,则会遇到切片问题。
    猜你喜欢
    • 2013-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多