std::tuple默认构造函数,带有move可构造元素



我试图返回一个std::tuple,其中包含一个不可复制可构造类型的元素。这似乎阻止了我使用默认的类构造函数来构造元组。例如,要返回包含Foo的元组,必须创建一个foo实例,并且std::moved:

class Foo {
public:
Foo(const Foo&) = delete;
Foo(Foo&&) = default;
int x;
};
tuple<int, Foo> MakeFoo() {
Foo foo{37};
//  return {42, {37}}; // error: could not convert ‘{42, {37}}’ from ‘’ to ‘std::tuple’
return {42, std::move(foo)};
}

另一方面,如果类被定义为具有复制构造函数,则元组的构造工作良好:

class Bar {
public:
Bar(const Bar&) = default;
int x;
};
tuple<int, Bar> MakeBar() {
return {42, {37}}; // compiles ok
}

有办法将MakeBar语法与Foo类一起使用吗

不完全正确,但您(至少(有两个选项。

你可以拼出Foo:

tuple<int, Foo> MakeFoo() {
return {42, Foo{37}}
}

或者,您可以向Foo添加一个构造函数,以替换您现在正在进行的聚合初始化:

class Foo {
public:
Foo(const Foo&) = delete;
Foo(Foo&&) = default;
Foo(int x) : x(x) {}      // <--
int x;
};
tuple<int, Foo> MakeFoo() {
return {42, 37};
}

但是为什么要写return {42, 37}而不是return {42, {37}}呢?为什么需要添加一个构造函数来实现这一点?

构造一个至少有一个只移动类型的元组意味着我们不能使用直接构造函数

tuple<Types...>::tuple(const Types &...)

相反,我们必须使用模板化的转换构造函数

template<class... UTypes>
tuple<Types...>::tuple(UTypes &&...)

因此,这两个自变量的类型将被推导出来。但是,{37}是一个初始值设定项列表,在这种情况下,它使第二个函数参数成为非推导上下文(请参见[temp.dexpract.type]/5.6(。因此,模板参数推导失败,构造函数无法调用。因此,我们必须编写return {42, 37}以使推导成功。

此外,只有当参数类型可转换为相应的元组元素类型时,此模板化转换构造函数才参与重载解析。并且可转换性不考虑聚合初始化,因此int不可转换为原始Foo。但是,如果我们添加转换构造函数Foo::Foo(int)int现在可以转换为Foo,并且可以调用tuple构造函数。

最新更新