Довольно часто в С++ 11 мне нужно определить функцию, которая принимает контейнер в качестве параметра.
Например, можно определить функцию addup
(да только простая версия std::accumulate
):
template <class I>
int addup (I first, I last)
{
int x = 0;
while ( first != last )
x += *first++;
return x;
}
Это принимает диапазон итераторов, который является гибким и стандартным идиомой библиотеки.
Однако предположим, что у меня есть функция:
vector<T> f();
Я должен сделать это:
auto v = f();
int x = addup(v.begin(), v.end());
Я бы скорее сделал это:
int x = addup(f());
Как я могу это сделать:
for (auto t : f())
...
В духе основанного на диапазонах я хотел бы что-то вроде этого:
template<class C>
int addup(C&& container)
{
addup(beginexpr(container), endexpr(container)); // ???
}
В стандарте говорится в 6.5.4 (перефразирование):
(A), если
container
- тип массива,beginexpr
иendexpr
являютсяcontainer
иcontainer
+bound
соответственно, гдеbound
- это граница массива.(B), если
container
является типом класса, unqualified-idsbegin
иend
просматриваются в области классаcontainer
, как если бы поиск по элементам класса (3.4.5), и если либо (или оба) найдут хотя бы одно объявление,beginexpr
иendexpr
являются container.begin() и container.end() соответственно;(C) в противном случае
beginexpr
иendexpr
равны соответственноbegin(container)
иend(container)
, где начало и конец просматриваются с зависимым от аргумента поиска (3.4.2).
Можно ли определить набор перегрузок или специализаций addup
, чтобы он обрабатывал четыре случая и не противоречил другим перегрузкам? Это, во-первых, регулярная функция пары итераторов, а затем каждая из A, B и C выше. Как?
(Если это возможно, то почему стандартная библиотека не предлагает такие перегрузки?)
Кроме того, что, если функция принимает дополнительные параметры за пределами контейнера? Можем ли мы модифицировать перегрузки таким образом, чтобы дополнительный добавочный параметр x
(один со значением по умолчанию), добавленный ко всем из них, не делал следующие два вызова неоднозначными:
addup(v.begin(), v.end());
addup(v, x);
То есть мы можем статически утверждать (используя "SFINAE" или подобное), что параметр шаблона должен быть итератором, массивом, классом контейнера и т.д. - и использовать эту информацию для значений перегрузки?