Reputation: 20264
As I have read, begin(some_vector)
is more standard than some_vector.begin()
because of array support... and as I know also, the use of using keyword
is not really desirable behavior. However, I also see lot of code that contains just these two usings
:
using std::begin;
using std::end;
Is that considered good or bad practice? Especially when many begin
and end
are needed?
Upvotes: 8
Views: 1821
Reputation: 171263
As I have read,
begin(some_vector)
is more standard thansome_vector.begin()
because of array support
It's not "more standard", both are 100% standard. It is more generic, because it works for arrays, but it's not actually very common to have an object and not know whether it's an array or a container type. If you have something that you know is an array then use std::begin(a)
but if you have something that you know is not an array then there is no advantage to using the form that also works with arrays. If you're in a generic context where you might have either, then std::begin
works for both cases.
the use of
using
keyword is not really desirable behavior.
That's debatable. There are very good reasons to avoid using-directives in most contexts (i.e. using namespace foo
) but the same arguments don't apply to using-declarations that introduce a single name (i.e. using foo::bar
). For example the recommended way to use std::swap
is via using std::swap
so it's certainly not true that the using
keyword is undesirable in general.
Is that considered good or bad practice? Especially when many begin and end are needed?
I would say that in general it's a bad idea. As the other answers explain, it allows begin
and end
to be found by ADL, but that's not necessarily a good thing. Enabling ADL for begin
and end
can cause problems, that's why we changed range-based for
at the last minute to not use using std::begin; using std::end;
to avoid ambiguities, see N3257 for the details.
Upvotes: 15
Reputation: 30605
Is that considered good or bad practice?
This depends a lot on the context; I think the answer is equally applicable to the more general question of introducing names via a using
. Limit the scope of the use of using
makes for more readable code (such as function level scope); use it as required, use it with care.
A particularly interesting case here revolves around ADL.
template <class Container>
void func(Container& c)
{
std::for_each(begin(c), end(c), /* some functor*/);
}
ADL is already in play, since if the container is from the std
namespace, the std::begin
and std::end
will be found. If the container is from a custom namespace, begin
and end
functions can be found in that namespace (for this discussion, I assume the container provider has also provided these).
If the container is a normal C-style array, the array form std::begin(T (&array)[N])
will not be found since the C-style array is not the std
namespace. Introducing a using std::begin
here allows the code to be used for arrays and containers.
template <class Container>
void func(Container& c)
{
using std::begin; // if c is an array, the function will still compile
using std::end;
std::for_each(begin(c), end(c), /* some functor*/);
}
// ...
int a[100];
func(a); // works as expected
Demo.
Upvotes: 5
Reputation: 55887
It can be helpful for ADL
help. Something like:
template<typename T, typename F>
void apply(T& v, const F& f)
{
using std::begin;
using std::end;
std::for_each(begin(v), end(v), f);
}
So, than we just can call apply
with types, that have begin/end
functions and classic C arrays.
In other case it's actually okay to use using
directive in source file, in little scope and so on, but it's bad to use in header.
Upvotes: 7
Reputation: 12757
It depends. Using declarations (and, far more, using directives) in header files are heavily discouraged. However, if inside the body of a function you use a lot of times one or several functions from another namespace, a using declaration / directives (put inside the body of the function, so limited to its scope) can make the code more readable.
Upvotes: 1