初始化一个不可复制和不可移动的类的元组

时间:2017-01-15 02:55:23

标签: c++ stdtuple

考虑使用唯一自定义构造函数的A类:

class A
{
public:
    A(float) {}

private:
    A() = delete;
    A(const A&) = delete;
    A(A&&) = delete;
};

另一个B类,它包含一个A元组(为了简单起见,让它成为唯一的元组成员):

class B
{
public:
    B() : ta(0.0f) {} // ta initialization OK

private:
    std::tuple<A> ta;
};

现在我们可以声明一个B的对象,它可以正常工作:

B b;

但如果A的构造函数有多个参数,如何做同样的事情?

class A
{
public:
    A(float, int) {}

private:
    A() = delete;
    A(const A&) = delete;
    A(A&&) = delete;
};

class B
{
public:
//  B() : ta(0.0f, 1) {} // Compilation errors
//  B() : ta({0.0f, 1}) {} // Compilation errors
//  B() : ta{0.0f, 1} {} // Compilation errors
//  B() : ta(A(0.0f, 1)) {} // No constructor to copy or move A

private:
    std::tuple<A> ta;
};

B b;

std::make_tuplestd::forward_as_tuple和其他类似内容无法解决问题,因为A的默认,复制和移动构造函数已被禁用。

1 个答案:

答案 0 :(得分:3)

std::tuple几乎无法在原地构建其成员。初始化tuple的一般预期方法是通过从组件对象复制/移动。

它允许将构造函数参数隐式转换为各自的参数。但这只是参数和tuple成员之间的1:1关系。构造函数参数与tuple成员之间无法建立多对一关系。

可以允许您的类型可以从tuple本身隐式构建:

class A
{
public:
    A(float, int) {}
    A(const std::tuple<float, int> &tpl)
        : A(std::get<0>(tpl), std::get<1>(tpl)) {}

private:
    A() = delete;
    A(const A&) = delete;
    A(A&&) = delete;
};

因此,您可以像这样构建tuple

class B
{
public:
    B() : ta(std::tuple<float, int>(0.0f, 1)) {}

private:
    std::tuple<A> ta;
};

如果你想使用更深入的元编程,你可能还可以创建一组构造函数,允许你的类型从tuple构造,其类型与任何可用的构造函数匹配:

class A
{
public:
    A(float, int) {}

    template<typename ...Args>
    A(const std::tuple<Args...> &args) : A(args, std::index_sequence_for<Args...>{}) {}

private:
    A() = delete;
    A(const A&) = delete;
    A(A&&) = delete;

    template<typename ...Args, std::size_t ...Is>
    A(const std::tuple<Args...> &args, std::index_sequence<Is...>) 
        : A(std::get<Is>(args)...) {}
};