首页 > 解决方案 > 是否可以从可变参数模板调用多个基类构造函数?

问题描述

我正在尝试为我正在处理的嵌入式项目中的外围设备创建一个抽象。问题是,并非所有人都以相同的方式行事,也没有相同的界面。

我正在尝试将 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");
}

真的有可能吗?如果是这样,我该怎么做?我也愿意接受有关如何解决此问题的建议。

标签: c++decoratorvariadic-templates

解决方案


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

 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})};
 }

推荐阅读