Я пытаюсь написать шаблонную функцию, которая будет суммировать все элементы некоторой коллекции - заданной либо как простой контейнер stl, либо как диапазон range-v3.(Действительная функция, как показано ниже, является немного более общей). Я думал, что это будет работать:
template <typename Range, typename Ret, typename Func>
std::pair<Ret, int> sum(const Range& range, Ret zero, Func extract) {
using It = decltype(range.begin());
Ret sum = zero;
int numElements = 0;
for (It it = range.begin(); it != range.end(); ++it) {
sum += extract(*it);
++numElements;
}
return { sum, numElements };
}
Это действительно работает для элементов STL, но не для диапазонов.Это дает мне очень длинную ошибку:
<this file, at line 'using It'> error C2662: 'ranges::v3::basic_iterator<ranges::v3::adaptor_cursor<ranges::v3::basic_iterator<ranges::v3::adaptor_cursor<std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<_Ty>>>,ranges::v3::iter_transform_view<Rng,ranges::v3::indirected<Fun>>::adaptor<false>>>,ranges::v3::remove_if_view<ranges::v3::transform_view<Rng,Fun>,ranges::v3::logical_negate_<EnemyGroup::stepUpdate::<lambda_c582fb1297dce111c4572cef649d86b9>>>::adaptor>> ranges::v3::view_facade<Derived,ranges::v3::finite>::begin<Derived,false,0x0>(void)': cannot convert 'this' pointer from 'const Range' to 'ranges::v3::view_facade<Derived,ranges::v3::finite> &'
note: Conversion loses qualifiers
Первоначально я думал, что это был некоторый недостаток ветки vs2015 range-v3.Недолго думая, я просто взломал быстрый обход:
template <typename Range, typename Ret, typename Func>
std::pair<Ret, int> sum(const Range& range, Ret zero, Func extract) {
using It = decltype(const_cast<Range*>(&range)->begin());
Ret sum = zero;
int numElements = 0;
for (It it = const_cast<Range*>(&range)->begin(); it != const_cast<Range*>(&range)->end(); ++it) {
//sum += extract(std::as_const(*it)); (does not work either, converts to void)
sum += extract(*it);
++numElements;
}
return { sum, numElements };
}
, но с новейшей версией MSVC, которая только что вышла из предварительного просмотра, теперь официально поддерживается основная ветвь диапазонов.Тем не менее, вышеупомянутая ошибка преобладает.
- Является ли использование объектов диапазона как
const&
неправильной вещью?Я знаю, что эти объекты легки и их легко копировать, но использование константной ссылки не должно повредить, или?С другой стороны, если передан конкретный контейнер STL, мне нужно передать его как const&
- Если использование
const&
неверно, есть ли какой-нибудь простой способ заставить функцию работать с обоими контейнерамии диапазоны, ничего не записывая на сайте вызовов (например, вызывая view::all
)
Я использую Visual Studio Community 2017, версия 15.9.3.Обратите внимание, что до 15.9 range-v3
в его основной ветке не поддерживалось.
Поскольку вы спрашиваете, как именно я это называю.Мой настоящий код сложен, но я сократил его до этого небольшого примера:
#include <set>
#include <range/v3/view/filter.hpp>
template <typename Range, typename Ret, typename Func>
std::pair<Ret, int> sum(const Range& range, Ret zero, Func extract) {
using It = decltype(range.begin());
Ret sum = zero;
int numElements = 0;
for (It it = range.begin(); it != range.end(); ++it) {
sum += extract(*it);
++numElements;
}
return { sum, numElements };
}
int main() {
std::set<int*> units;
auto [vsum, num] = sum(
units | ranges::v3::view::filter([](const int* eu) { return *eu>0; }),
0,
[](const int* eu) { return *eu/2; }
);
}
Это дает мне те же ошибки преобразования, что и выше.