提问人:jwezorek 提问时间:9/30/2023 最后编辑:jwezorek 更新时间:10/1/2023 访问量:669
在这种情况下,为什么需要指定默认构造对象的类型?
Why do I need to specify the type of a default constructed object in this situation?
问:
我不明白为什么在下面我需要指定,而我没有:foobar
std::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
答:
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 我实际上注意到裸 {} 版本适用于一对,并且也想知道这一点。
评论