When to use std::begin and std::end instead of container specific versions
If you look at, say, the definition of std::begin
:
template< class C >
auto begin( C& c ) -> decltype(c.begin());
You see that all it does is reference the begin()
anyway. I suppose a decent compiler will make the difference nil, so I guess it comes down to preference. Personally, I'd use cont.begin()
and cont.end()
just so that I wouldn't have to explain it to anybody :)
As Mooing Duck points out, however, std::begin
also works on arrays:
template< class T, size_t N >
T* begin( T (&array)[N] );
... so there is that to consider. If you are not using arrays, I'd go with my suggestion. However if you are unsure if what is passed is going to be an STL container, or an array of <T>
, then std::begin()
is the way to go.
Difference between vector::begin() and std::begin()
std::begin()
was added in C++11 to make it easier to write generic code (e.g. in templates). The most obvious reason for it is that plain C-style arrays do not have methods, hence no .begin()
. So you can use std::begin()
with C-style arrays, as well as STL-style containers having their own begin()
and end()
.
If you're writing code which is not a template, you can ignore std::begin()
; your fellow programmers would probably find it odd if you suddenly started using it everywhere just because it's new.
Relying on ADL for std::begin() and std::end()?
If you're going to use ADL to be able to change the container type without changing the loops, then add using std::begin; using std::end;
. That makes sure it finds the std
functions for containers from other namespaces that have begin
and end
members, but no free functions in their namespace.
namespace my {
template <typename T>
struct container {
// ... stuff
iterator begin();
iterator end();
};
// no begin/end free functions
}
my::container<int> vec = get_vec();
using std::begin;
using std::end;
for (auto it = begin(vec), end = end(vec); it != end; ++it) { /*...*/ }
// defaults to std::begin which defaults to .begin() member function
Why use non-member begin and end functions in C++11?
How do you call .begin()
and .end()
on a C-array ?
Free-functions allow for more generic programming because they can be added afterwards, on a data-structure you cannot alter.
Should custom containers have free begin/end functions?
There are several approaches, each with their own pros and cons. Below three approaches with a cost-benefit analysis.
ADL through custom non-member begin()
/ end()
The first alternative provides non-member begin()
and end()
function templates inside a legacy
namespace to retrofit the required functionality onto any class or class template that can provide it, but has e.g. the wrong naming conventions. Calling code can then rely on ADL to find these new functions. Example code (based on comments by @Xeo):
// LegacyContainerBeginEnd.h
namespace legacy {
// retro-fitting begin() / end() interface on legacy
// Container class template with incompatible names
template<class C>
auto begin(Container& c) -> decltype(c.legacy_begin())
{
return c.legacy_begin();
}
// similarly for begin() taking const&, cbegin(), end(), cend(), etc.
} // namespace legacy
// print.h
template<class C>
void print(C const& c)
{
// bring into scope to fall back on for types without their own namespace non-member begin()/end()
using std::begin;
using std::end;
// works for Standard Containers, C-style arrays and legacy Containers
std::copy(begin(c), end(c), std::ostream_iterator<decltype(*begin(c))>(std::cout, " ")); std::cout << "\n";
// alternative: also works for Standard Containers, C-style arrays and legacy Containers
for (auto elem: c) std::cout << elem << " "; std::cout << "\n";
}
Pros: consistent and terse calling convention that works completely generically
- works for any Standard Container and user-types that define member
.begin()
and.end()
- works for C-style arrays
- can be retrofitted to work (also for range-for loops!) for any class template
legacy::Container<T>
that does not have member.begin()
andend()
without requiring source code modifications
Cons: requires using-declarations in many places
std::begin
andstd::end
are required to have been brought into every explicit calling scope as fall back options for C-style arrays (potential pitfall for template headers and general nuisance)
ADL through custom non-member adl_begin()
and adl_end()
A second alternative is to encapsulate the using-declarations of the previous solution into a separate adl
namespace by providing non-member function templates adl_begin()
and adl_end()
, which can then also be found through ADL. Example code (based on comments by @Yakk):
// LegacyContainerBeginEnd.h
// as before...
// ADLBeginEnd.h
namespace adl {
using std::begin; // <-- here, because otherwise decltype() will not find it
template<class C>
auto adl_begin(C && c) -> decltype(begin(std::forward<C>(c)))
{
// using std::begin; // in C++14 this might work because decltype() is no longer needed
return begin(std::forward<C>(c)); // try to find non-member, fall back on std::
}
// similary for cbegin(), end(), cend(), etc.
} // namespace adl
using adl::adl_begin; // will be visible in any compilation unit that includes this header
// print.h
# include "ADLBeginEnd.h" // brings adl_begin() and adl_end() into scope
template<class C>
void print(C const& c)
{
// works for Standard Containers, C-style arrays and legacy Containers
std::copy(adl_begin(c), adl_end(c), std::ostream_iterator<decltype(*adl_begin(c))>(std::cout, " ")); std::cout << "\n";
// alternative: also works for Standard Containers, C-style arrays and legacy Containers
// does not need adl_begin() / adl_end(), but continues to work
for (auto elem: c) std::cout << elem << " "; std::cout << "\n";
}
Pros: consistent calling convention that works completely generically
- the same pros as for @Xeo's suggestion +
- the repeated using-declarations have been encapsulated (DRY)
Cons: a little verbose
adl_begin()
/adl_end()
is not as terse asbegin()
/end()
- it is perhaps also not as idiomatic (although it is explicit)
- pending C++14 return type deduction, will also pollute namespace with
std::begin
/std::end
NOTE: Not sure if this really improves upon the previous approach.
Explicitly qualifying std::begin()
or std::end()
everywhere
Once the verbosity of begin()
/ end()
has been given up anyway, why not go back to the qualified calls of std::begin()
/ std::end()
? Example code:
// LegacyIntContainerBeginEnd.h
namespace std {
// retro-fitting begin() / end() interface on legacy IntContainer class
// with incompatible names
template<>
auto begin(legacy::IntContainer& c) -> decltype(c.legacy_begin())
{
return c.legacy_begin();
}
// similary for begin() taking const&, cbegin(), end(), cend(), etc.
} // namespace std
// LegacyContainer.h
namespace legacy {
template<class T>
class Container
{
public:
// YES, DOCUMENT REALLY WELL THAT THE EXISTING CODE IS BEING MODIFIED
auto begin() -> decltype(legacy_begin()) { return legacy_begin(); }
auto end() -> decltype(legacy_end()) { return legacy_end(); }
// rest of existing interface
};
} // namespace legacy
// print.h
template<class C>
void print(C const& c)
{
// works for Standard Containers, C-style arrays as well as
// legacy::IntContainer and legacy::Container<T>
std::copy(std::begin(c), std::end(c), std::ostream_iterator<decltype(*std::begin(c))>(std::cout, " ")); std::cout << "\n";
// alternative: also works for Standard Containers, C-style arrays and
// legacy::IntContainer and legacy::Container<T>
for (auto elem: c) std::cout << elem << " "; std::cout << "\n";
}
Pros: consistent calling convention that works almost generically
- works for any Standard Container and user-types that define member
.begin()
and.end()
- works for C-style arrays
Cons: a little verbose and retrofitting is not generic and a maintainence problem
std::begin()
/std::end()
is a little more verbose thanbegin()
/end()
- can only be retrofitted to work (also for range-for loops!) for any class
LegacyContainer
that does not have member.begin()
andend()
(and for which there is no source code!) by providing explicit specializations of the non-member function templatesbegin()
andend()
innamespace std
- can only be retrofitted onto class templates
LegacyContainer<T>
by directly adding member functionsbegin()
/end()
inside the source code ofLegacyContainer<T>
(which for templates is available). Thenamespace std
trick does not work here because function templates cannot be partially specialized.
What to use?
The ADL approach through non-member begin()
/ end()
in a a container's own namespace is the idiomatic C++11 approach, especially for generic functions that require retrofitting on legacy classes and class templates. It is the same idiom as for user-providing non-member swap()
functions.
For code that only uses Standard Containers or C-style arrays, std::begin()
and std::end()
could be called everywhere without introducing using-declarations, at the expense of more verbose calls. This approach can even be retrofitted but it requires fiddling with namespace std
(for class types) or in-place source modifcations (for class templates). It can be done, but is not worth the maintainence trouble.
In non-generic code, where the container in question is known at coding-time, one could even rely on ADL for Standard Containers only, and explicitly qualify std::begin
/ std::end
for C-style arrays. It loses some calling consistency but saves on using-declarations.
what is the preferred way to expose custom STL-style iteration?
I suggest creating both sets of functions -- member functions as well as non-member functions -- to allow for maximum flexibility.
namespace JDanielSmith {
class C
{
const size_t _size;
const std::unique_ptr<int[]> _data;
public:
C(size_t size) : _size(size), _data(new int[size]) {}
inline const int* get() const { return _data.get(); }
inline int* get() { return _data.get(); }
size_t size() const { return _size; }
int* begin() { return get(); }
int* end() { return get() + _size; }
const int* begin() const { return get(); }
const int* end() const { return get() + _size; }
const int* cbegin() const { return get(); }
const int* cend() const { return get() + _size; }
};
int* begin(C& c) { return c.begin(); }
int* end(C& c) { return c.end(); }
const int* begin(C const& c) { return c.begin(); }
const int* end(C const& c) { return c.end(); }
const int* cbegin(C const& c) { return c.begin(); }
const int* cend(C const& c) { return c.end(); }
}
The member functions are necessary if you want to be able to use objects of type C
as arguments to std::begin
, std::end
, std::cbegin
, and std::cend
.
The non-member functions are necessary if you want to be able to use objects of type C
as arguments to just begin
, end
, cbegin
, and cend
. ADL will make sure that the non-member functions will be found for such usages.
int main()
{
JDanielSmith::C c1(10);
{
// Non-const member functions are found
auto b = std::begin(c1);
auto e = std::end(c1);
for (int i = 0; b != e; ++b, ++i )
{
*b = i*10;
}
}
JDanielSmith::C const& c2 = c1;
{
// Const member functions are found
auto b = std::begin(c2);
auto e = std::end(c2);
for ( ; b != e; ++b )
{
std::cout << *b << std::endl;
}
}
{
// Non-member functions with const-objects as argument are found
auto b = begin(c2);
auto e = end(c2);
for ( ; b != e; ++b )
{
std::cout << *b << std::endl;
}
}
}
Invoking begin and end via using-directive?
Using a using
-declaration like that is the correct way IMO. It's also what the standard does with the range for loop: if there is no begin
or end
members present then it will call begin(x)
and end(x)
with std
as an associated namespace (i.e. it will find std::begin
and std::end
if ADL doesn't find non-member begin
and end
).
If you find that writing using std::begin; using std::end;
all the time is tedious then you can use the adl_begin
and adl_end
functions below:
namespace aux {
using std::begin;
using std::end;
template<class T>
auto adl_begin(T&& x) -> decltype(begin(std::forward<T>(x)));
template<class T>
auto adl_end(T&& x) -> decltype(end(std::forward<T>(x)));
template<class T>
constexpr bool is_array()
{
using type = typename std::remove_reference<T>::type;
return std::is_array<type>::value;
}
} // namespace aux
template<class T,
class = typename std::enable_if<!aux::is_array<T>()>::type>
auto adl_begin(T&& x) -> decltype(aux::adl_begin(std::forward<T>(x)))
{
using std::begin;
return begin(std::forward<T>(x));
}
template<class T,
class = typename std::enable_if<!aux::is_array<T>()>::type>
auto adl_end(T&& x) -> decltype(aux::adl_end(std::forward<T>(x)))
{
using std::end;
return end(std::forward<T>(x));
}
template<typename T, std::size_t N>
T* adl_begin(T (&x)[N])
{
return std::begin(x);
}
template<typename T, std::size_t N>
T* adl_end(T (&x)[N])
{
return std::end(x);
}
This code is pretty monstrous. Hopefully with C++14 this can become less arcane:
template<typename T>
concept bool Not_array()
{
using type = std::remove_reference_t<T>;
return !std::is_array<type>::value;
}
decltype(auto) adl_begin(Not_array&& x)
{
using std::begin;
return begin(std::forward<Not_array>(x));
}
decltype(auto) adl_end(Not_array&& x)
{
using std::end;
return end(std::forward<Not_array>(x));
}
template<typename T, std::size_t N>
T* adl_begin(T (&x)[N])
{
return std::begin(x);
}
template<typename T, std::size_t N>
T* adl_end(T (&x)[N])
{
return std::end(x);
}
Related Topics
5 Years Later, Is There Something Better Than the "Fastest Possible C++ Delegates"
C++: Where to Initialize Variables in Constructor
C++ Reading the Data Part of a Wav File
How to Give Priority to Privileged Thread in Mutex Locking
What Are the Use Cases for Having a Function Return by Const Value for Non-Builtin Type
C/C++ Changing the Value of a Const
How to Create a Sparse Array in C++
Openmp Set_Num_Threads() Is Not Working
C++ on X86-64: When Are Structs/Classes Passed and Returned in Registers
What Exactly Does Stringstream Do
Default, Value and Zero Initialization Mess
How to Change String into Qstring
How to Construct a Std::String from a Std::Vector<Char>