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
container
is an array type,beginexpr
andendexpr
arecontainer
andcontainer
+bound
, respectively, wherebound
is the array bound.(B) if
container
is a class type, the unqualified-idsbegin
andend
are looked up in the scope of classcontainer
as if by class member access lookup (3.4.5), and if either (or both) finds at least one declaration,beginexpr
andendexpr
are container.begin() and container.end(), respectively;(C) otherwise,
beginexpr
andendexpr
arebegin(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?
Range-based for loop in C++ Range-based for loop in C++ is added since C++ 11. It executes a for loop over a range. Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container.
Use the range-based for statement to construct loops that must execute through a range, which is defined as anything that you can iterate through—for example, std::vector , or any other C++ Standard Library sequence whose range is defined by a begin() and end() .
This is what I would do:
template<class Range>
int addup(Range&& range)
{
using std::begin;
using std::end;
addup(begin(range), end(range)); // begin(), NOT std::begin() (ADL)
}
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.
the following two calls ambiguous:
I haven't compiled, but I don't see any ambiguity there unless x
needs an implicit conversion. You can also use boost::make_iterator_range
and avoid having an iterator parameter overload.
I think this will also work:
template<class Range>
int addup(Range&& range)
{
int x = 0;
for(auto&& v : range)
x += v;
return x;
}
template <class I>
int addup (I first, I last)
{
return addup(boost::make_iterator_range(first, last));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With