无法从 initializer_list 移动的解决方法?

问题描述 投票:0回答:1

方便的

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;
}

如果我理解正确的话,这是因为取消引用初始化迭代器会给出

const T
,即使在尝试移动时也会被复制。

有解决方法吗?

阅读https://stackoverflow.com/a/44307741/889742,提出了一种使用可变参数模板的解决方案,如下:

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)...);
}

( aside1:这声明了一个数组,它会被优化掉吗?
aside2:

void
在表达中的含义和目的是什么?好像没必要 )

随着 C++20 和 C++23 的新变化,现在是否有更好的解决方法?

c++ c++20 move-semantics initializer-list c++23
1个回答
0
投票

如果您可以等待 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

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

编译时类型

<A>
参数不是强制性的,可以推导出来,前提是所有参数都具有相同的类型。 如果 exra cullly 括号很烦人,
std::make_array
正在测试中。目前还没有按标准出货,但是会省略
std::to_array
需要的花括号。 另一种选择是接受原始数组作为函数输入并使用
std::move_itarator
:

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()});

这个看起来像

std::to_array
版本,但它不是 std 库的一部分——因为数组是特殊情况。 有很多可能的组合,但几乎所有组合都依赖于复制省略——它从 C++11 开始作为优化选项,并从 C++17 开始一直是强制性的。

© www.soinside.com 2019 - 2024. All rights reserved.