是否可以从可变参数模板调用多个基类构造函数?

时间:2019-07-16 16:27:14

标签: c++ decorator variadic-templates

我正在尝试为我正在从事的嵌入式项目中的外围设备创建抽象。问题是,并非所有人都表现出相同的行为方式,也不具有相同的界面。

我正在尝试将CRTP与“静态装饰器”设计模式一起使用,但是由于无法使用可变参数模板调用多个基类构造器,所以我被困在CommunicableDevice构造器中。

#include <iostream>
​
    struct Interface
    {
        Interface(int pin) {}
​
        virtual void write()
        {
        }
​
        virtual void read()
        {
        }
    };
​
    struct RTSCTSInterface : public Interface
    {
        template <typename ... Args>
        RTSCTSInterface(int rts, Args&& ... args)
            : Interface(std::forward<Args>(args)...), rts(rts)
        {}
​
        void write() override
        {
        }
​
        int rts;
    };
​
    struct Powerable
    {
​
        Powerable(int dummy) : dummy(dummy)
        {}
​
        void turnOn()
        {
        }
​
        int dummy;
    };
​
    struct Device
    {
        Device(const std::string& name) : name(name){}
​
        std::string name;
    };

    template <typename CustomDevice>
    struct PowerableDevice : public Powerable, public CustomDevice
    {
        template <typename ... Args>
        PowerableDevice(int dummy, Args&&... args)
            : Powerable(dummy), CustomDevice(std::forward<Args>(args)...)
        {}
    };
​
    template <typename CustomInterface, typename CustomDevice>
    struct CommunicableDevice : public CustomInterface, public CustomDevice
    {
        template <typename ... Args>
        CommunicableDevice(Args&&... args)
        // call constructors with args
        {
​
        }
    };
​
int main()
{
    CommunicableDevice<RTSCTSInterface, PowerableDevice<Device>> dev(1, 2, 300, 5, "dummy");
}

实际上有可能吗?如果是这样,我该怎么办?我也欢迎提出有关如何解决此问题的建议。

1 个答案:

答案 0 :(得分:2)

  

我不知道如何使用可变参数模板调用多个基类构造函数。

 template <typename CustomInterface, typename CustomDevice>
 struct CommunicableDevice : public CustomInterface, public CustomDevice
 {
     template <typename ... Args>
     CommunicableDevice(Args&&... args)
     // call constructors with args
     {
     }
 };

我看不到一般的解决方法。

问题是:哪个参数用于第一个基类,哪个参数用于第二个基类?

我想到的唯一解决方案是将每个基类的参数包装在std::tuple中。然后使用委托的构造函数和索引序列来提取它们。

我的意思是(简化示例:没有完美的转发)

template <typename CI, typename CD>
struct foo : public CI, public CD
 {
   private:
      template <typename ... As, typename ... Bs, std::size_t ... Ia,
                std::size_t ... Ib>
      foo (std::tuple<As...> const & ta, std::tuple<Bs...> const & tb,
           std::index_sequence<Ia...>, std::index_sequence<Ib...>)
        : CI(std::get<Ia>(ta)...), CD(std::get<Ib>(tb)...)
       { }

   public:
      template <typename ... As, typename ... Bs>
      foo (std::tuple<As...> const & ta, std::tuple<Bs...> const & tb)
        : foo(ta, tb, std::index_sequence_for<As...>{},
              std::index_sequence_for<Bs...>{})
       { }
 };

糟糕的是,您必须调用构造元组的构造函数

foo<bar1, bar2> f{std::make_tuple(1, 2l, "3", 4ull), // <-- for bar1
/* for bar2 --> */std::make_tuple(5, "6", std::vector<int>{7, 8, 9})};

以下是完整的C ++ 14示例

#include <tuple>
#include <string>
#include <vector>
#include <type_traits>

template <typename CI, typename CD>
struct foo : public CI, public CD
 {
   private:
      template <typename ... As, typename ... Bs, std::size_t ... Ia,
                std::size_t ... Ib>
      foo (std::tuple<As...> const & ta, std::tuple<Bs...> const & tb,
           std::index_sequence<Ia...>, std::index_sequence<Ib...>)
        : CI(std::get<Ia>(ta)...), CD(std::get<Ib>(tb)...)
       { }

   public:
      template <typename ... As, typename ... Bs>
      foo (std::tuple<As...> const & ta, std::tuple<Bs...> const & tb)
        : foo(ta, tb, std::index_sequence_for<As...>{},
              std::index_sequence_for<Bs...>{})
       { }
 };

struct bar1
 { 
   template <typename ... Ts>
   bar1 (int, long, Ts...)
    { }
 };

struct bar2
 { 
   template <typename ... Ts>
   bar2 (int, std::string, Ts...)
    { }
 };

int main ()
 {
   foo<bar1, bar2> f{std::make_tuple(1, 2l, "3", 4ull),
                     std::make_tuple(5, "6", std::vector<int>{7, 8, 9})};
 }