代码之家  ›  专栏  ›  技术社区  ›  Ton van den Heuvel

是否可以避免在以下代码中使用复制/移动构造函数?

  •  4
  • Ton van den Heuvel  · 技术社区  · 6 年前

    对于可以组成不同mixin类型的类型,请考虑以下代码。复合类型的构造函数采用元组的可变列表,元组表示复合类型的构造函数的参数:

    #include <string>
    #include <tuple>
    #include <utility>
    
    struct MixinBase {
      MixinBase() = default;
      // Note; want to delete these instead of default them.
      MixinBase(const MixinBase&) = default;
      MixinBase(MixinBase&&) = default;
    };
    
    struct MixinA : public MixinBase {
      MixinA(int, const std::string&, const std::string&) {}
    };
    
    struct MixinB : public MixinBase {
      MixinB(const std::string&, const std::string&) {}
    };
    
    template <typename... Mixins>
    struct Composition : private Mixins... {
      template <typename... Packs>
      Composition(Packs&&... packs)
          : Mixins(constructMixin<Mixins>(
                std::forward<Packs>(packs),
                std::make_index_sequence<std::tuple_size_v<Packs>>{}))...
      {
      }
    
    private:
      template <typename Mixin, typename Pack, size_t... Indexes>
      Mixin constructMixin(Pack&& arguments, std::index_sequence<Indexes...>) const
      {
        return Mixin(std::get<Indexes>(std::forward<Pack>(arguments))...);
      }
    };
    
    int main()
    {
      std::string a{"a"};
      std::string b{"b"};
    
      Composition<MixinA, MixinB>(
          std::forward_as_tuple(7, a, b), std::forward_as_tuple(a, b));
    
      return 0;
    }
    

    constructMixin ,并直接构造每个继承的mixin对象,以避免对mixin类型使用复制/移动构造函数。这可能吗?

    2 回复  |  直到 6 年前
        1
  •  4
  •   xskxzr    6 年前

    您可以定义一个helper类来支持分段构造:

    template <typename T>
    struct Piecewise_construct_wrapper : T {
        template <typename Tuple>
        Piecewise_construct_wrapper(Tuple&& t) : 
            Piecewise_construct_wrapper(std::forward<Tuple>(t), 
                                        std::make_index_sequence<std::tuple_size_v<Tuple>>{}) {}
    
        template <typename Tuple, size_t... Indexes>
        Piecewise_construct_wrapper(Tuple&& t, std::index_sequence<Indexes...>) : 
            T(std::get<Indexes>(std::forward<Tuple>(t))...) {}
    };
    

    Composition Piecewise_construct_wrapper<Mixins>... :

    template <typename... Mixins>
    struct Composition : private Piecewise_construct_wrapper<Mixins>... {
        template <typename... Packs>
        Composition(Packs&&... packs)
            : Piecewise_construct_wrapper<Mixins>(std::forward<Packs>(packs))...
        {
        }
    };
    
        2
  •  3
  •   Barry    6 年前

    您需要Mixins来选择直接允许分段构造。不幸的是,这是相当重复的,所以您可以使用如下宏:

    #define PIECEWISE_CONSTRUCT(Type)                               \
      template <typename Tuple>                                     \
      Type(std::piecewise_construct_t, Tuple&& tuple)               \
        : Type(std::piecewise_construct,                            \
            std::forward<Tuple>(tuple),                             \
            std::make_index_sequence<std::tuple_size_v<Tuple>>())   \
      { }                                                           \  
      template <typename Tuple, size_t... Indexes>                  \
      Type(std::piecewise_construct_t, Tuple&& tuple,               \
            std::index_sequence<Indexes...>)                        \
        : Type(std::get<Indexes>(std::forward<Tuple>(tuple))...)    \
      { }
    

    用作:

    struct MixinA : public MixinBase {
      MixinA(int, const std::string&, const std::string&) {}
    
      PIECEWISE_CONSTRUCT(MixinA)
    };
    
    struct MixinB : public MixinBase {
      MixinB(const std::string&, const std::string&) {}
    
      PIECEWISE_CONSTRUCT(MixinB)
    };
    
    template <typename... Mixins>
    struct Composition : private Mixins... {
      template <typename... Packs>
      Composition(Packs&&... packs)
          : Mixins(std::piecewise_construct, std::forward<Packs>(packs))...
      { }
    };
    

    不幸的是,保证的副本省略在构造子对象时无法工作-所以这可能是您的最佳选择。我不认为你能在没有嵌套包的情况下直接做到这一点?很有可能我只是没有足够的创造力,如果有人提出更好的东西,我会非常好奇。