创建一个 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。我的用途仅用于指针,所以不是问题。