#c #range-v3
#c #диапазон-v3
Вопрос:
Рассмотрим следующую программу:
#include <iostream>
#include <algorithm>
#include <numeric>
#include <array>
#include <range/v3/view/transform.hpp>
int main() {
using container = std::array<std::tuple<int,float,double>, 4>;
container tuples {{
{1, 4.f, 8.},
{2, 5.f, 9.},
{3, 6.f, 10.},
{4, 7.f, 11.}
}};
auto int_view =
tuples | ranges::view::transform( [](autoamp; t){return std::get<int>(t);} );
// int_view[1] = 3; // (*)
auto x = std::accumulate(int_view.begin(), int_view.end(), 0);
std::cout << "x = " << x << std::endl;
}
Это компилируется и печатается 10
; но — если я раскомментирую (*)
строку — она не компилируется, а GCC жалуется на то, что левая часть равенства не является значением lvalue . Я был немного разочарован этим — я надеялся, что преобразование приведет к созданию intamp;
‘s, которые я мог бы назначить…
Могу ли я что-нибудь сделать из этого изменяемого представления? Или какой-либо другой механизм в библиотеке ranges, который позволил бы мне эквивалент изменяемого представления?
Ответ №1:
Проблема с вашим кодом очень проста, если вы подумаете об этом:
Функция преобразования на самом деле является проекционной функцией, и ваша функция не создает ссылки, необходимые для разрешения модификации источника, потому что стандартное правило вывода возвращаемого типа для лямбд использует правила для простых auto
, и они никогда не выводят ссылки.
-
Одним из исправлений является изменение правил вычета для
decltype(auto)
, которые сохраняют ссылки, и поэтому их лучше избегать, если вы не знаете, что они верны.auto int_view = tuples | ranges::view::transform( [](autoamp; t)->decltype(auto){return std::get<int>(t);});
-
Или вы можете явно запросить ссылки с
autoamp;
помощью или чего-то более конкретного.auto int_view = tuples | ranges::view::transform( [](autoamp; t)->autoamp;{return std::get<int>(t);});
-
И, наконец, никто не мешает вам возвращать прокси, подобный
std::reference_wrapper
. Хотя это ненужное усложнение.auto int_view = tuples | ranges::view::transform( [](autoamp; t){return std::ref(std::get<int>(t));});