创建一个 to_vector 函数,该函数可以根据输出类型有条件地转换为输入范围的元素
create a to_vector function that can conditionally const cast to elements of input range based on output type
我想创建一个与输入 vieweable_ranges 一起工作的 to_vector 函数。如果输入视图和输出向量具有完全相同的类型,我可以很容易地让它工作,但如果输出需要对输入范围的元素进行 const 转换,我就无法让它工作。在我的例子中,输入范围有非常量指针,但输出可能指定 const 指针。我想像这样使用它:
auto a = to_vector( view ); // returns a vector<obj *>. This case is easy
vector<const obj *> b = to_vector( view ); // returns a vector of const pointers. This gives error shown at the end
标准库在制作向量时转换指针没有问题
vector<const obj *> c( view.begin(), view.end() );
但我无法创建模板函数来使其工作。我尝试了很多变体,但我认为我最接近的想法是这样的:
#include <ranges>
#include <vector>
using namespace std::ranges;
template <range Range, typename T = range_value_t<Range>> // default element type, T, based on input range
inline std::vector<T> to_vector(Range&& r) { // idea: user specifies T. (doesn't work)
std::vector<T> v;
if constexpr (std::ranges::sized_range<T>) {
v.reserve(std::ranges::size(r));
}
std::copy(std::ranges::begin(r), std::ranges::end(r), std::back_inserter(v));
return v;
}
to_vector 可以编译,但是当我尝试要求向量输出时出现错误,错误如下:
cannot convert std::vector<Obj *,std::allocator<Obj *>>' to
'std::vector<const Obj *,std::allocator<const Obj *>>
这是因为您的函数创建了一个 return 类型 std::vector<Obj*>
的值,这确实是与 std::vector<const Obj*>
不同的类型;因此,除非 std::vector
提供了一个重载的构造函数,它接受了自身的非常量版本,否则这种转换是不可能的。 return 值不是由您将函数结果分配给的值推导出来的,而是由 T
模板参数推导出来的,因此如果您使用 T=const Obj*
[= 显式调用该函数,这将起作用16=]
您需要显式重载函数以构造 const 对象的向量,方法是传递虚拟标记参数、额外的模板参数或 to_const_vector
函数。
按照 Dominic Price 的建议,我将模板函数拆分为两个单独的函数。第一个适用于所有对象,但调用约定可能稍微麻烦一些。第二个使用 const 指针,并且很难获得 std::views.
的类型
template <range R, typename T = range_value_t<R> >
inline auto to_vector(R &&r) {
return std::vector<T>(r.begin(), r.end()); // treats sized ranges correctly
}
template <range R, typename T>
inline auto to_vector(R &&r, T &&) {
return std::vector<T>(r.begin(), r.end()); // treats sized ranges correctly
}
这允许调用者使用如下语法:
struct Unit {};
using UnitPtr = Unit const *;
using Units = vector<UnitPtr>;
unordered_set<Unit *> clusters; // clusters could even be a rvalue view
auto u = to_vector(clusters); // will return vector<Unit *>
Units v = to_vector<Clusters, UnitPtr>(clusters); // need typenames...
Units w = to_vector(clusters, UnitPtr()); // ... or this for convertable
这可能有一个缺点,即可能构造参数 T is。我的用途仅用于指针,所以不是问题。
我想创建一个与输入 vieweable_ranges 一起工作的 to_vector 函数。如果输入视图和输出向量具有完全相同的类型,我可以很容易地让它工作,但如果输出需要对输入范围的元素进行 const 转换,我就无法让它工作。在我的例子中,输入范围有非常量指针,但输出可能指定 const 指针。我想像这样使用它:
auto a = to_vector( view ); // returns a vector<obj *>. This case is easy
vector<const obj *> b = to_vector( view ); // returns a vector of const pointers. This gives error shown at the end
标准库在制作向量时转换指针没有问题
vector<const obj *> c( view.begin(), view.end() );
但我无法创建模板函数来使其工作。我尝试了很多变体,但我认为我最接近的想法是这样的:
#include <ranges>
#include <vector>
using namespace std::ranges;
template <range Range, typename T = range_value_t<Range>> // default element type, T, based on input range
inline std::vector<T> to_vector(Range&& r) { // idea: user specifies T. (doesn't work)
std::vector<T> v;
if constexpr (std::ranges::sized_range<T>) {
v.reserve(std::ranges::size(r));
}
std::copy(std::ranges::begin(r), std::ranges::end(r), std::back_inserter(v));
return v;
}
to_vector 可以编译,但是当我尝试要求向量输出时出现错误,错误如下:
cannot convert std::vector<Obj *,std::allocator<Obj *>>' to 'std::vector<const Obj *,std::allocator<const Obj *>>
这是因为您的函数创建了一个 return 类型 std::vector<Obj*>
的值,这确实是与 std::vector<const Obj*>
不同的类型;因此,除非 std::vector
提供了一个重载的构造函数,它接受了自身的非常量版本,否则这种转换是不可能的。 return 值不是由您将函数结果分配给的值推导出来的,而是由 T
模板参数推导出来的,因此如果您使用 T=const Obj*
[= 显式调用该函数,这将起作用16=]
您需要显式重载函数以构造 const 对象的向量,方法是传递虚拟标记参数、额外的模板参数或 to_const_vector
函数。
按照 Dominic Price 的建议,我将模板函数拆分为两个单独的函数。第一个适用于所有对象,但调用约定可能稍微麻烦一些。第二个使用 const 指针,并且很难获得 std::views.
的类型template <range R, typename T = range_value_t<R> >
inline auto to_vector(R &&r) {
return std::vector<T>(r.begin(), r.end()); // treats sized ranges correctly
}
template <range R, typename T>
inline auto to_vector(R &&r, T &&) {
return std::vector<T>(r.begin(), r.end()); // treats sized ranges correctly
}
这允许调用者使用如下语法:
struct Unit {};
using UnitPtr = Unit const *;
using Units = vector<UnitPtr>;
unordered_set<Unit *> clusters; // clusters could even be a rvalue view
auto u = to_vector(clusters); // will return vector<Unit *>
Units v = to_vector<Clusters, UnitPtr>(clusters); // need typenames...
Units w = to_vector(clusters, UnitPtr()); // ... or this for convertable
这可能有一个缺点,即可能构造参数 T is。我的用途仅用于指针,所以不是问题。