#c #templates #return-type
#c #шаблоны #возвращаемый тип
Вопрос:
Я хотел бы создать функцию to_vector, которая работает с входными данными vieweable_ranges. Я могу легко заставить это работать, если входной вид и выходной вектор имеют точно такой же тип, но не могу заставить его работать, если для вывода требуется постоянное приведение элементов входного диапазона. В моем случае входные диапазоны имеют неконстантные указатели, но на выходе могут указываться указатели const. Я хочу использовать его примерно так:
auto a = to_vector( view ); // returns a vectorlt;obj *gt;. This case is easy vectorlt;const obj *gt; b = to_vector( view ); // returns a vector of const pointers. This gives error shown at the end
Стандартная библиотека не имеет проблем с приведением указателей при создании вектора
vectorlt;const obj *gt; c( view.begin(), view.end() );
Но я не могу создать шаблонную функцию, чтобы она работала. Я перепробовал много вариантов, но я думаю, что моя ближайшая идея-что-то вроде этого:
#include lt;rangesgt; #include lt;vectorgt; using namespace std::ranges; template lt;range Range, typename T = range_value_tlt;Rangegt;gt; // default element type, T, based on input range inline std::vectorlt;Tgt; to_vector(Rangeamp;amp; r) { // idea: user specifies T. (doesn't work) std::vectorlt;Tgt; v; if constexpr (std::ranges::sized_rangelt;Tgt;) { v.reserve(std::ranges::size(r)); } std::copy(std::ranges::begin(r), std::ranges::end(r), std::back_inserter(v)); return v; }
To_vector компилируется, но я получаю ошибку, когда пытаюсь запросить векторный вывод с ошибкой примерно такой:
не удается преобразовать std::векторlt;Obj *,std::распределительlt;Obj *gt;lt;Obj *gt;gt;’ в ‘std::векторlt;Obj *gt;gt;lt;const Obj *,std::распределительlt;const Obj *gt;lt;const Obj *gt;gt;
Ответ №1:
Как предложил Доминик Прайс, я разделил функцию шаблона на две отдельные функции. Первый работает со всеми объектами, но может иметь несколько более громоздкое соглашение о вызовах. Второй работает с указателями const, и там, где трудно получить тип std::представления.
template lt;range R, typename T = range_value_tlt;Rgt; gt; inline auto to_vector(R amp;amp;r) { return std::vectorlt;Tgt;(r.begin(), r.end()); // treats sized ranges correctly } template lt;range R, typename Tgt; inline auto to_vector(R amp;amp;r, T amp;amp;) { return std::vectorlt;Tgt;(r.begin(), r.end()); // treats sized ranges correctly }
Это позволяет использовать следующий синтаксис от вызывающего абонента примерно так:
struct Unit {}; using UnitPtr = Unit const *; using Units = vectorlt;UnitPtrgt;; unordered_setlt;Unit *gt; clusters; // clusters could even be a rvalue view auto u = to_vector(clusters); // will return vectorlt;Unit *gt; Units v = to_vectorlt;Clusters, UnitPtrgt;(clusters); // need typenames... Units w = to_vector(clusters, UnitPtr()); // ... or this for convertable
Это может иметь тот недостаток, что аргумент T может быть сконструирован. Я использую только указатели, так что это не проблема.
Ответ №2:
Это связано с тем , что ваша функция создает возвращаемое значение типа std::vectorlt;Obj*gt;
, которое действительно отличается от типа std::vectorlt;const Obj*gt;
; и поэтому, если std::vector
не предоставлен перегруженный конструктор, который принял неконстантную версию самого себя, это преобразование невозможно. Возвращаемое значение выводится не по значению, которому вы присваиваете результат функции, а по параметру T
шаблона, поэтому это будет работать, если вы явно вызовете функцию с T=const Obj*
Вам потребуется явно перегрузить функцию, чтобы построить вектор объектов const, либо передав параметр фиктивного тега, дополнительный параметр шаблона или to_const_vector
функцию.
Комментарии:
1. std::вектор действительно предоставляет неконстантную версию самого себя. он также предоставляет тот, который принимает итераторы к неконстантным элементам и преобразует их в const. Но до сих пор я думаю, что вы правы в том, что, если я ограничу интерфейс to_vector тем, что я предоставил, нет никакого способа заставить компилятор вывести то, что я хочу. Я вижу, что это краткое описание языка и того, как он определен для обработки контейнеров const, элементов const и представлений const.
2. Что вы подразумеваете под «std::вектор предоставляет неконстантную версию самого себя»? Я предполагал, что преобразование будет возможно только с помощью конструктора с подписью
vector(const vectorlt;std::remove_constlt;Tgt;::typegt;amp;)
3. Я понимаю. Я имел в виду, что для преобразования можно использовать итераторную версию конструкторов, как в примере в op.