Quite frequently in C++11 I need to define a function that takes a container as a parameter.
For example lets define a function addup (yes just a simple version of std::accumulate):
template <class I>
int addup (I first, I last)
{
int x = 0;
while ( first != last )
x += *first++;
return x;
}
This takes an iterator range, which is flexible and the standard library idiom.
However suppose I have a function:
vector<T> f();
I have to do this:
auto v = f();
int x = addup(v.begin(), v.end());
I would rather just do this:
int x = addup(f());
Just like I can do this:
for (auto t : f())
...
In the spirit of range-based for I would like something like this:
template<class C>
int addup(C&& container)
{
addup(beginexpr(container), endexpr(container)); // ???
}
In the standard it says in 6.5.4 (paraphrasing):
(A) if
containeris an array type,beginexprandendexprarecontainerandcontainer+bound, respectively, whereboundis the array bound.(B) if
containeris a class type, the unqualified-idsbeginandendare looked up in the scope of classcontaineras if by class member access lookup (3.4.5), and if either (or both) finds at least one declaration,beginexprandendexprare container.begin() and container.end(), respectively;(C) otherwise,
beginexprandendexprarebegin(container)andend(container), respectively, where begin and end are looked up with argument-dependent lookup (3.4.2).
Is it possible to define a set of overloads or specializations of addup such that it will handle the four cases, and not conflict with other overloads? That is firstly a regular iterator pair function, and then each of A, B and C above. How?
(If this is possible than why doesn’t the standard library offer such overloads?)
Also, what if the function takes extra parameters beyond the container? Can we modify the overloads in such a way that an optional extra parameter x (one with a default value) added to all of them will not make the following two calls ambiguous:
addup(v.begin(), v.end());
addup(v, x);
That is can we statically assert (using "SFINAE" or similar) that the template parameter has to be an iterator, an array, a container class, etc – and have this information used for overload disambiguation?
This is what I would do:
It will handle all the important cases and does ADL properly. I’m not sure if it’s equivalent to what ranged-based-for does but in my opinion it is the best solution.
I haven’t compiled, but I don’t see any ambiguity there unless
xneeds an implicit conversion. You can also useboost::make_iterator_rangeand avoid having an iterator parameter overload.I think this will also work: