Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoking begin and end via using-directive?

The established idiom for invoking swap is:

using std::swap
swap(foo, bar);

This way, swap can be overloaded for user-defined types outside of the std namespace.

Should we invoke begin and end in the same fashion?

using std::begin;
using std::end;
some_algorithm(begin(some_container), end(some_container));

Or should we just write:

some_algorithm(std::begin(some_container), std::end(some_container));
like image 873
fredoverflow Avatar asked Sep 13 '13 07:09

fredoverflow


People also ask

What is using directive in C#?

The using directive allows you to use types defined in a namespace without specifying the fully qualified namespace of that type. In its basic form, the using directive imports all the types from a single namespace, as shown in the following example: C# Copy. using System.

What is using static?

The using static DirectiveThis directive allows us to reference static members without needing to reference the namespace or even the type itself. using static directives can also be used to reference nested types. The WriteLine method that we've been using in our examples is a static member of the Console class.

What is namespace used for in C#?

The namespace keyword is used to declare a scope that contains a set of related objects. You can use a namespace to organize code elements and to create globally unique types. namespace SampleNamespace; class AnotherSampleClass { public void AnotherSampleMethod() { System. Console.


1 Answers

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);
}
like image 179
Simple Avatar answered Oct 16 '22 18:10

Simple