在这种情况下,为什么需要指定默认构造对象的类型?

Why do I need to specify the type of a default constructed object in this situation?

提问人:jwezorek 提问时间:9/30/2023 最后编辑:jwezorek 更新时间:10/1/2023 访问量:669

问:

我不明白为什么在下面我需要指定,而我没有:foobarstd::vector<int>{}foobar2

#include <iostream>
#include <memory>
#include <vector>
#include <tuple>

std::tuple<std::unique_ptr<int>, std::vector<int>> foobar() {
    std::unique_ptr<int> test = std::make_unique<int>(42);
    return { std::move(test), {} };    // <= this is a syntax error
    // return { std::move(test), std::vector<int>{} }  // <= this compiles...
}

std::tuple<int, std::vector<int>> foobar2() {
    return { {},  {} };
}

int main() {
    std::cout << *std::get<0>(foobar()) << "\n";
    std::cout << std::get<0>(foobar2()) << "\n";
    return 0;
}

来自 GCC 的错误消息是

<source>: In function 'std::tuple<std::unique_ptr<int, std::default_delete<int> >, std::vector<int, std::allocator<int> > > foobar()':
<source>:8:34: error: could not convert '{std::move<unique_ptr<int>&>(test), <brace-enclosed initializer list>()}' from '<brace-enclosed initializer list>' to 'std::tuple<std::unique_ptr<int, std::default_delete<int> >, std::vector<int, std::allocator<int> > >'
    8 |     return { std::move(test), {} };    // <= this is a syntax error
      |                                  ^
      |                                  |
      |                                  <brace-enclosed initializer list>
Compiler returned: 1
c++ std 默认构造函数 stdtuple

评论


答:

14赞 Sam Varshavchik 9/30/2023 #1

给定一个

template< class... Types >
class tuple;

这里可以使用两种可能的构造函数。第一个是:

tuple( const Types&... args );

但是,仅当所有元组成员都可复制构造时,才能使用它。当然,它不是可复制构造的。unique_ptr

这只剩下另一个可能的构造函数:

template< class... UTypes >
tuple( UTypes&&... args );

也就是说,一个转发构造函数,一个将其所有参数转发到每个基础元组成员的构造函数的“Hail Mary”。

{}

空的 braced-init 列表是无类型的,不能绑定到转发引用。

如果只有一个构造函数,这可能会起作用:

tuple(Types && ... Args);

如果所有成员类型都是可移动的,则参与重载解析。唉,没有。

而在 foobar2 中,我不:

foobar2的元组成员是可复制构造的。使用第一个构造函数重载。

评论

1赞 Brian Bi 10/1/2023
他们为 C++23 中的一个构造函数添加了默认模板参数,解决了这样的问题。遗憾的是,您不能在当前的 C++23 中默认包,因此此解决方案不适用于元组。(但我听说有一个提议。pair
0赞 jwezorek 10/1/2023
@BrianBi 我实际上注意到裸 {} 版本适用于一对,并且也想知道这一点。