繁体   English   中英

将元组扩展到成员初始值设定项列表中的参数包

[英]Expand tuple to parameters pack in member initializer lists

我需要使用存储在 std::tuple 中的 arguments 来初始化基本 class。 我可以访问 C++17 并设法找出 std::make_from_tuple 可能有效,但需要基本 class 的复制构造函数。

一个例子:

#include <tuple>

template<class Base>
class WithTupleConstructor : public Base // Sort of a Mixin class template
{
    public:

    // Creating a Base with arguments stored in tuple and then copying it
    template<class Tuple>
    WithTupleConstructor(const Tuple& base_args)
    : Base(std::make_from_tuple<Base>(base_args)) }
    { }
};

class WithCopyConstructor
{
    public:
    
    WithCopyConstructor(int a, int b)
    {};
    WithCopyConstructor(const WithCopyConstructor& other)
    {};
};

class WithoutCopyConstructor
{
    public:
    WithoutCopyConstructor(int a)
    {};
    WithoutCopyConstructor(const WithoutCopyConstructor& other) = delete;
};

int main()
{
  WithTupleConstructor<WithCopyConstructor> m1(std::make_tuple(1,2));

  // this do not compiles
  //WithTupleConstructor<WithoutCopyConstructor> m2(std::make_tuple(1));
}

std::make_index_sequence 和 std::get 似乎需要一个辅助 function 并且看不到如何使用它们来解决这个问题(如tuple-to-parameter-pack所述)。

有没有办法在不需要复制构造函数的情况下扩展初始化列表中的元组?

std::make_from_tuple将返回一个类型Base ,然后Base的复制构造函数将使用它来创建m1m2 ,正如您所提到的。

我不知道我在下面展示的不同方法是否适合您:

  • WithTupleConstructor只是将元组转发到Base
  • 每个Base都有一个接收特定元组的构造函数。

[演示]

#include <fmt/core.h>
#include <tuple>
#include <utility>  // forward

template<typename Base>
struct WithTupleConstructor : public Base {
    template<typename Tuple>
    WithTupleConstructor(Tuple&& base_args)
    : Base{ std::forward<Tuple>(base_args) }
    {}
};

struct WithCopyConstructor {
    int a_{};
    int b_{};

    WithCopyConstructor(std::tuple<int,int>&& t)
    : a_{std::move(std::get<0>(t))}, b_{std::move(std::get<1>(t))} {}
    WithCopyConstructor(int a, int b) {};
    WithCopyConstructor(const WithCopyConstructor& other) {};
};

struct WithoutCopyConstructor {
    int a_{};

    WithoutCopyConstructor(std::tuple<int>&& t)
    : a_{std::move(std::get<0>(t))} {}
    WithoutCopyConstructor(int a) {};
    WithoutCopyConstructor(const WithoutCopyConstructor& other) = delete;
};

int main() {
    WithTupleConstructor<WithCopyConstructor> m1(std::tuple{1,2});
    WithTupleConstructor<WithoutCopyConstructor> m2(std::tuple{1});

    fmt::print("m1: ({}, {})\n", m1.a_, m1.b_);
    fmt::print("m2: ({})\n", m2.a_);
}

// Outputs:
//
//   m1: (1, 2)
//   m2: (1)

我在这个答案中找到了一个解决方案,结果证明它可以使用 std::make_index_sequence 和 std::get 来实现。

需要一个“解包”元组的辅助 function,但它可以定义为私有构造函数:

#include <tuple>

template<typename Tuple>
using make_tuple_index_sequence = std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>;

template<class Base>
class WithTupleConstructor : public Base // Sort of a Mixin class template
{
    public:

    // Passing tuple and index sequence to auxiliary constructor
    template<class Tuple>
    WithTupleConstructor(const Tuple& base_args)
    : WithTupleConstructor(base_args, make_tuple_index_sequence<Tuple>{})
    { }

    private:

    // Expanding tuple using std::get
    template<class Tuple, std::size_t ...tuple_n>
    WithTupleConstructor(const Tuple& base_args, std::index_sequence<tuple_n...> )
    :  Base(std::get<tuple_n>(base_args)...)
    {

    }
};

class WithCopyConstructor
{
    public:
    
    WithCopyConstructor(int a, int b)
    {}
    WithCopyConstructor(const WithCopyConstructor& other)
    {}
};

class WithoutCopyConstructor
{
    public:
    WithoutCopyConstructor(int a)
    {}
    WithoutCopyConstructor(const WithoutCopyConstructor& other) = delete
};

int main()
{
  WithTupleConstructor<WithCopyConstructor> m1(std::make_tuple(1,2));

  WithTupleConstructor<WithoutCopyConstructor> m2(std::make_tuple(1));
}

通过在接收和传递元组时添加 && 和 std::forward 可以进一步扩展以支持右值和完美转发。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM