如何构造具有唯一指针的向量
How to construct a vector with unique pointers
我尝试用 unique_ptr 构造一个向量。但是我没有找到直接的方法。以下代码无法编译。错误 is:Call to implicitly-deleted copy constructor of 'std::__1::unique_ptr >':
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
class test1{
public:
test1(){};
test1(test1&&)=default;
};
int main(int argc, const char * argv[]) {
std::unique_ptr<test1> us(new test1());
std::vector<std::unique_ptr<test1>> vec{move(us)};
return 0;
}
你正在调用 vector
constructor ((7) on the linked page) that takes an initializer_list<T>
argument. An initializer_list
only allows const
access 到它的元素,所以 vector
必须复制元素,这当然无法编译。
以下应该有效
std::unique_ptr<test1> us(new test1());
std::vector<std::unique_ptr<test1>> vec;
vec.push_back(move(us));
// or
vec.push_back(std::unique_ptr<test1>(new test1()));
// or
vec.push_back(std::make_unique<test1>()); // make_unique requires C++14
您可以使用带有两个迭代器的 vector
构造函数,但解决方案仍然不是单行的,因为它需要您定义一个临时数组,然后您可以从中移动。
std::unique_ptr<test1> arr[] = {std::make_unique<test1>()};
std::vector<std::unique_ptr<test1>> vec{std::make_move_iterator(std::begin(arr)),
std::make_move_iterator(std::end(arr))};
这个 make_vector
是一个函数,它接受任意数量的参数,并将它们完美地转发到一个向量中。
// get the first type in a pack, if it exists:
template<class...Ts>
struct first {};
template<class T, class...Ts>
struct first<T,Ts...>{
using type=T;
};
template<class...Ts>
using first_t=typename first<Ts...>::type;
// build the return type:
template<class T0, class...Ts>
using vector_T =
typename std::conditional<
std::is_same<T0, void>::value,
typename std::decay<first_t<Ts...>>::type,
T0
>::type;
template<class T0, class...Ts>
using vector_t = std::vector< vector_T<T0, Ts...> >;
// make a vector, non-empty arg case:
template<class T0=void, class...Ts, class R=vector_t<T0, Ts...>>
R make_vector( Ts&&...ts ) {
R retval;
retval.reserve(sizeof...(Ts)); // we know how many elements
// array unpacking trick:
using discard = int[];
(void)discard{0,((
retval.emplace_back( std::forward<Ts>(ts) )
),void(),0)...};
return retval; // NRVO!
}
// the empty overload:
template<class T>
std::vector<T> make_vector() {
return {};
}
使用:
std::vector<std::unique_ptr<test1>> vec =
make_vector(
std::move(u1), std::move(u2)
);
我打磨了一下。如果您向它传递 1 个或多个参数并且不向它传递类型,它将推断出 return 类型。如果你传递给它一个类型,它就会使用那个类型。如果您未能将类型或任何参数传递给它,它会抱怨。 (如果你转发包,或者以特定类型存储它,我总是给它一个类型)。
可以做进一步的步骤,我们进行 return 类型推导以消除指定类型的要求,即使在空的情况下也是如此。这在你的用例中可能是必需的,我不知道,但它符合你不需要指定 {}
类型的方式,所以我想我会把它扔在那里:
template<class...Ts>
struct make_vec_later {
std::tuple<Ts...> args; // could make this `Ts&&...`, but that is scary
// make this && in C++14
template<class T, size_t...Is>
std::vector<T> get(std::index_sequence<Is...>) {
return make_vector<T>(std::get<Is>(std::move(args))...);
}
// make this && in C++14
template<class T>
operator std::vector<T>(){
return std::move(*this).template get<T>( std::index_sequence_for<Ts...>{} );
}
};
template<class...Ts>
make_vec_later<Ts...> v(Ts&&...ts) {
return {std::tuple<Ts...>(std::forward<Ts>(ts)...)};
}
这确实依赖于 index_sequence
的 C++14 功能,但如果您的编译器还没有,则很容易在 C++11 中重写这些功能。只是google栈溢出,有无数种实现。
现在语法如下:
std::vector<std::unique_ptr<test1>> vec =
v(std::move(u1));
参数列表可以为空。
支持变体分配器留给用户作为练习。将另一种类型添加到 make_vector
,称为 A
,并将其默认为 void
。如果它是无效的,则将其交换为 std::allocator<T>
以用于为向量选择的任何类型 T
。在return类型推导版本中,做类似的事情。
我尝试用 unique_ptr 构造一个向量。但是我没有找到直接的方法。以下代码无法编译。错误 is:Call to implicitly-deleted copy constructor of 'std::__1::unique_ptr >':
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
class test1{
public:
test1(){};
test1(test1&&)=default;
};
int main(int argc, const char * argv[]) {
std::unique_ptr<test1> us(new test1());
std::vector<std::unique_ptr<test1>> vec{move(us)};
return 0;
}
你正在调用 vector
constructor ((7) on the linked page) that takes an initializer_list<T>
argument. An initializer_list
only allows const
access 到它的元素,所以 vector
必须复制元素,这当然无法编译。
以下应该有效
std::unique_ptr<test1> us(new test1());
std::vector<std::unique_ptr<test1>> vec;
vec.push_back(move(us));
// or
vec.push_back(std::unique_ptr<test1>(new test1()));
// or
vec.push_back(std::make_unique<test1>()); // make_unique requires C++14
您可以使用带有两个迭代器的 vector
构造函数,但解决方案仍然不是单行的,因为它需要您定义一个临时数组,然后您可以从中移动。
std::unique_ptr<test1> arr[] = {std::make_unique<test1>()};
std::vector<std::unique_ptr<test1>> vec{std::make_move_iterator(std::begin(arr)),
std::make_move_iterator(std::end(arr))};
这个 make_vector
是一个函数,它接受任意数量的参数,并将它们完美地转发到一个向量中。
// get the first type in a pack, if it exists:
template<class...Ts>
struct first {};
template<class T, class...Ts>
struct first<T,Ts...>{
using type=T;
};
template<class...Ts>
using first_t=typename first<Ts...>::type;
// build the return type:
template<class T0, class...Ts>
using vector_T =
typename std::conditional<
std::is_same<T0, void>::value,
typename std::decay<first_t<Ts...>>::type,
T0
>::type;
template<class T0, class...Ts>
using vector_t = std::vector< vector_T<T0, Ts...> >;
// make a vector, non-empty arg case:
template<class T0=void, class...Ts, class R=vector_t<T0, Ts...>>
R make_vector( Ts&&...ts ) {
R retval;
retval.reserve(sizeof...(Ts)); // we know how many elements
// array unpacking trick:
using discard = int[];
(void)discard{0,((
retval.emplace_back( std::forward<Ts>(ts) )
),void(),0)...};
return retval; // NRVO!
}
// the empty overload:
template<class T>
std::vector<T> make_vector() {
return {};
}
使用:
std::vector<std::unique_ptr<test1>> vec =
make_vector(
std::move(u1), std::move(u2)
);
我打磨了一下。如果您向它传递 1 个或多个参数并且不向它传递类型,它将推断出 return 类型。如果你传递给它一个类型,它就会使用那个类型。如果您未能将类型或任何参数传递给它,它会抱怨。 (如果你转发包,或者以特定类型存储它,我总是给它一个类型)。
可以做进一步的步骤,我们进行 return 类型推导以消除指定类型的要求,即使在空的情况下也是如此。这在你的用例中可能是必需的,我不知道,但它符合你不需要指定 {}
类型的方式,所以我想我会把它扔在那里:
template<class...Ts>
struct make_vec_later {
std::tuple<Ts...> args; // could make this `Ts&&...`, but that is scary
// make this && in C++14
template<class T, size_t...Is>
std::vector<T> get(std::index_sequence<Is...>) {
return make_vector<T>(std::get<Is>(std::move(args))...);
}
// make this && in C++14
template<class T>
operator std::vector<T>(){
return std::move(*this).template get<T>( std::index_sequence_for<Ts...>{} );
}
};
template<class...Ts>
make_vec_later<Ts...> v(Ts&&...ts) {
return {std::tuple<Ts...>(std::forward<Ts>(ts)...)};
}
这确实依赖于 index_sequence
的 C++14 功能,但如果您的编译器还没有,则很容易在 C++11 中重写这些功能。只是google栈溢出,有无数种实现。
现在语法如下:
std::vector<std::unique_ptr<test1>> vec =
v(std::move(u1));
参数列表可以为空。
支持变体分配器留给用户作为练习。将另一种类型添加到 make_vector
,称为 A
,并将其默认为 void
。如果它是无效的,则将其交换为 std::allocator<T>
以用于为向量选择的任何类型 T
。在return类型推导版本中,做类似的事情。