Gon*_*n I 9 c++ initializer-list move-semantics c++20 c++23
方便的initializer_list语法似乎是以无法移动列表成员、创建不必要的副本为代价的。
struct A
{
// some members which are dynamic resources...
A() { cout << "Default Constructor\n"; }
A(const A& original) { cout << "Copy constructor\n"; }
A(A&& original) { cout << "Move constructor\n"; }
};
int main() {
vector<A> v1{ A() , A() }; // calls copy
vector<A> v2;
v2.push_back(A()); v2.push_back(A()); // calls move
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,这是因为取消引用初始化器迭代器会给出const T,即使尝试移动时也会复制它。
有解决方法吗?
阅读/sf/answers/3101541901/,提出了一种使用可变参数模板的解决方案,如下所示:
template<class Array> struct maker;
// a maker which makes a std::vector
template<class T, class A>
struct maker<std::vector<T, A>>
{
using result_type = std::vector<T, A>;
template<class...Ts>
auto operator()(Ts&&...ts) const -> result_type
{
result_type result;
result.reserve(sizeof...(Ts));
using expand = int[];
void(expand {
0,
(result.push_back(std::forward<Ts>(ts)),0)...
});
return result;
}
};
// a maker which makes std::array
template<class T, std::size_t N>
struct maker<std::array<T, N>>
{
using result_type = std::array<T, N>;
template<class...Ts>
auto operator()(Ts&&...ts) const
{
return result_type { std::forward<Ts>(ts)... };
}
};
//
// delegation function which selects the correct maker
//
template<class Array, class...Ts>
auto make(Ts&&...ts)
{
auto m = maker<Array>();
return m(std::forward<Ts>(ts)...);
}
Run Code Online (Sandbox Code Playgroud)
(aside1:这声明了一个数组,它会被优化掉吗? aside2:表达式中的
含义和目的是什么?似乎没有必要)void
随着 C++20 和 C++23 的新变化,现在是否有更好的解决方法来解决这一切?
如果您可以等待 C++23,范围可以提供帮助:
#include <array>
#include <ranges>
auto v= std::array{A(),A()} //c++17
| std::views::as_rvalue //c++23
| std::ranges::to<std::vector>(); //c++23
Run Code Online (Sandbox Code Playgroud)
array构造函数使用 CTAD 从第一个输入推断出类型,并从输入数量推断出大小。休息是不言自明的。to_array如果仅必须显式指定类型,则可以使用构造函数代替:
#include <array>
#include <ranges>
auto v= std::to_array<A>({A(),A()}) //c++20
| std::views::as_rvalue //c++23
| std::ranges::to<std::vector>(); //c++23
Run Code Online (Sandbox Code Playgroud)
编译时类型<A>参数不是强制性的,只要所有参数都具有相同的类型,就可以推断出编译时类型参数。如果额外的花括号很烦人,std::make_array正在测试中。它尚未按照标准发布,但它将省略std::to_array所需的花括号。另一种选择是接受原始数组作为函数输入并使用std::move_iterator:
template<typename T, std::size_t N>
std::vector<T> to_vector(T (&&arr)[N]){
return std::vector<T>(
std::make_move_iterator(std::begin(arr)),//c++11
std::make_move_iterator(std::end(arr)));
};
auto v = to_vector({A(),A()});
Run Code Online (Sandbox Code Playgroud)
这个看起来像这个std::to_array版本,但它不是 std 库的一部分 - 因为数组是特殊情况。有很多可能的组合,但几乎所有组合都依赖于复制省略 - 它最初是 C++11 的优化选项,自 C++17 以来一直是强制的。
| 归档时间: |
|
| 查看次数: |
306 次 |
| 最近记录: |