使用初始化列表初始化unique_ptr的容器,继续

时间:2018-05-31 16:38:05

标签: c++

我想初始化std::vector的{​​{1}}和std::mapstd::unique_ptr<T>。就我而言,T是固定的。在这个例子中,我假设T = int,虽然实际上它是一个基类,从中派生出一堆其他类。

我一直在研究答案:

https://stackoverflow.com/a/46771893/4875652

并且我没有设法让它适用于std::map案例。

以下作品:

#include <memory>
#include <vector>

struct movable_il {
  mutable iptr t;
  operator iptr() const&& { return std::move(t); }
  movable_il( iptr&& in ): t(std::move(in)) {}
};

std::vector<iptr> vector_from_il( std::initializer_list<movable_il> il ) {
  return std::vector<iptr>( std::make_move_iterator(il.begin()), std::make_move_iterator(il.end()) );
}

int main()
{
    auto lol = vector_from_il({iptr{new int{3}}});

   return 0;
}

但是,以下情况并非如此:

#include <memory>
#include <map>
#include <utility>

using iptr = std::unique_ptr<int>;

struct movable_il {
  mutable std::pair<std::string, iptr> t;
  operator std::pair<std::string, iptr>() const&& { return std::move(t); }
  movable_il( std::pair<std::string, iptr>&& in ): t(std::move(in)) {}
};

std::map<std::string, iptr> container_from_il( std::initializer_list< movable_il> il ) {
  return std::map<std::string, iptr>( std::make_move_iterator(il.begin()), std::make_move_iterator(il.end()) );
}

int main()
{
    auto lol = container_from_il({std::pair<std::string, iptr>{"a", iptr{new int{3}}}});

   return 0;
}

有什么想法吗?

更新

我设法获得的最简单的工作示例,即尽可能与原始代码相似,而不是使用模板,是:

#include <iostream>
#include <map>
#include <memory>
#include <utility>

struct movable_pair {
  using first_type = std::string;
  using second_type = std::unique_ptr<int>;
  using pair_type = std::pair<const first_type, second_type>;
  first_type first;
  mutable second_type second;
  operator pair_type() const && { return {first, std::move(second)}; }
  movable_pair(pair_type &&in): first{in.first}, second{std::move(in.second)} {}
};

auto map_from_il(std::initializer_list<movable_pair> il) {
  return std::map<std::string, std::unique_ptr<int>>(std::make_move_iterator(il.begin()),
                                                     std::make_move_iterator(il.end()));
}

// Main function
int main() {
  using iptr = std::unique_ptr<int>;
  auto lol = map_from_il({{{"a", iptr{new int{3}}}}, {{"b", iptr{new int{2}}}}});

  // Small print-out to check we inserted the correct elements :)
  for (auto &l : lol) {
    std::cout << l.first << " " << *l.second << std::endl;
  }

  return 0;
}

向用户Banan寻求帮助,特别是找出所需的额外花括号。

1 个答案:

答案 0 :(得分:1)

据我所知,主要问题是你需要让pair移动。这完全由movable_il类完成,但现在您在尝试构建map时遇到了麻烦,因为firstsecond成员未定义{ {1}}。

由于你正在尝试从迭代器构造movable_il,我不会想象你会通过自己进行迭代并手动插入元素来看到任何性能损失。我已经基于此做出了解决方案。它不是最漂亮的解决方案,但它会完成这项工作。

此外,我还有一些问题需要编译器从map&#34;初始化列表&#34;中推导出T的正确类型,因此我创建了一个小辅助函数{{1创建这些,在这种情况下编译器没有问题。

pair

免责声明:我仅使用GCC 8.1.0对此进行了测试(但我无法想象使用其他编译器的任何问题)。

更新:如果在将对传递给movable_pair时放入了#include <memory> #include <map> #include <utility> #include <iostream> #include <vector> // Wrapper class to make type T "movable" template<class T> struct movable_il { mutable T t; operator T() const&& { return std::move(t); } movable_il( T&& in ): t(std::move(in)) {} T get() const { return std::move(t); } }; // Some template magic to deduce the correct value_type // ( not really needed for this example as we are mostly interested in maps ) template<class VT> struct fix_vt { using type = VT; }; template<class VT> using fix_vt_t = typename fix_vt<VT>::type; template<class VT> struct fix_vt<const VT> : fix_vt<VT> {}; template<class K, class V> struct fix_vt< std::pair<K,V> > { using type = std::pair< typename std::remove_cv<K>::type, typename std::remove_cv<V>::type >; }; // Create map from initializer list of movable T (pairs) template<class C, class T = fix_vt_t<typename C::value_type> > auto map_from_il(std::initializer_list< movable_il<T> > il) { using map_type = C; auto map = map_type{}; // Loop over il list and insert each element into the map for(auto&& entry : il) { map.insert(std::move(entry.get())); // We get the pair from the movable class and insert it by moving } return map; } // Helper function to create movable pair template<class First, class Second> auto movable_pair(First&& f, Second&& s) { using pair_type = std::pair<First, Second>; return movable_il<pair_type>{ pair_type{ std::forward<First>(f), std::forward<Second>(s) } }; } // Main function int main() { using iptr = std::unique_ptr<int>; using key_type = std::string; using value_type = iptr; using map_type = std::map<key_type, value_type>; auto lol = map_from_il<map_type>({ movable_pair("a", iptr{ new int {3} } ), movable_pair("b", iptr{ new int {2} }) }); // Small print-out to check we inserted the correct elements :) for(auto& l : lol) { std::cout << l.first << " " << *l.second << std::endl; } return 0; } {的额外集合,代码将在不使用}辅助函数。

map_from_il

更新2:如果您将以下构造函数添加到movable_pair,则代码也会在没有额外auto lol = map_from_il<map_type>({ { {"a", iptr{ new int {3} } } }, { {"b", iptr{ new int {2} } } } }); movable_il的情况下进行编译:

{

有了这个,你可以写:

}