with uso sirve reservada referencias que programacion para palabra mediante las integradas glosario comandos codigos bloque c++ c++11 stl using-directives argument-dependent-lookup

c++ - uso - para que sirve el this en c#



¿Invocar comenzar y terminar a través de la directiva using? (4)

El idioma establecido para invocar swap es:

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

De esta manera, el swap se puede sobrecargar para los tipos definidos por el usuario fuera del std nombres std .

¿Debemos invocar begin y end de la misma manera?

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

O deberíamos simplemente escribir:

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


Si su some_container es un contenedor estándar, std :: prefix es innecesario

#include <iostream> #include <vector> #include <algorithm> int main(){ std::vector<int>v { 1, 7, 1, 3, 6, 7 }; std::sort( begin(v), end(v) ); // here ADL search finds std::begin, std::end }


Usar una declaración de uso como esa es la forma correcta de IMO. También es lo que hace el estándar con el rango para el bucle: si no hay miembros begin o end presentes, llamará a begin(x) y end(x) con std como espacio de nombres asociado (es decir, encontrará std::begin y std::end si ADL no encuentra el begin y el end no sean miembros).

Si encuentras eso escribiendo using std::begin; using std::end; using std::begin; using std::end; todo el tiempo es tedioso, entonces puede usar las funciones adl_begin y adl_end continuación:

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); }

Este código es bastante monstruoso. Esperemos que con C ++ 14 esto pueda volverse menos arcano:

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); }


la documentation de swap especifica que el idioma al que se refiere es una práctica común en la biblioteca stl

Muchos componentes de la biblioteca estándar (dentro de estándar) intercambian llamadas de manera no calificada para permitir que se llamen sobrecargas personalizadas para tipos no fundamentales en lugar de esta versión genérica: sobrecargas personalizadas de intercambio declaradas en el mismo espacio de nombres que el tipo para el que están siempre que se seleccione mediante una búsqueda dependiente del argumento sobre esta versión genérica.

No existe tal cosa en la documentación para begin y end .

Por esta razón, definitivamente puede utilizar el

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

convención de llamada, pero debe tener en cuenta que se trata de una convención que no se aplica, por ejemplo, a algoritmos estándar, sino solo a su código.


Descargo de responsabilidad: para los tipos pedantes (o pedantes, si quiere ser pedante ...), generalmente me refiero a la palabra "sobrecarga" aquí como "Crear funciones que tengan los nombres begin y end y using std::begin; using std::end; " , lo cual, créeme, no es tedioso para mí escribir, pero es muy difícil de leer y es redundante de leer. :p.

Básicamente le daré los posibles casos de uso de dicha técnica, y luego mi conclusión.

Caso 1: sus métodos de begin y end no actúan como los de los contenedores estándar

Una situación en la que puede necesitar sobrecargar las funciones std::begin y std::end es cuando utiliza los métodos de begin y end de su tipo de una manera diferente a la de proporcionar un acceso similar a un iterador a los elementos de un objeto, y desea tener sobrecargas de std::begin y std::end llaman a los métodos de inicio y finalización utilizados para la iteración.

struct weird_container { void begin() { std::cout << "Start annoying user." } void end() { std::cout << "Stop annoying user." } iterator iter_begin() { /* return begin iterator */ } iterator iter_end() { /* return end iterator */ } }; auto begin(weird_container& c) { return c.iter_begin(); } auto end(weird_container& c) { return c.iter_end(); }

Sin embargo, no deberías y no deberías hacer una locura, ya que el rango para se rompería si se usara con un objeto de weird_container , según las reglas de range-for, el weird_container::begin() y el weird_container::end() métodos se encontrarían antes de las variantes de la función autónoma.

Por lo tanto, este caso trae un argumento para no usar lo que ha propuesto, ya que rompería una característica muy útil del lenguaje.

Caso 2 - los métodos de begin y end no están definidos en absoluto

Otro caso es cuando no se definen los métodos de begin y end . Este es un caso más común y aplicable, cuando desea extender su tipo para que sea iterativo sin modificar la interfaz de clase.

struct good_ol_type { ... some_container& get_data(); ... }; auto begin(good_ol_type& x) { return x.get_data().begin(); } auto end(good_ol_type& x) { return x.get_data().end(); }

¡Esto le permitiría usar algunas características ingeniosas en good_ol_type (algoritmos, rango-para, etc.) sin modificar realmente su interfaz! Esto está en línea con la recomendación de Herb Sutter de extender la funcionalidad de los tipos a través de funciones que no sean miembros no amigos.

Este es el buen caso, en el que realmente desea sobrecargar std:;begin y std::end .

Conclusión

Como nunca he visto a alguien hacer algo así en el primer caso (excepto en mi ejemplo), entonces realmente querrá usar lo que ha propuesto y sobrecargar std::begin y std::end siempre que sea aplicable.

No incluí aquí el caso donde definió los métodos de begin y end , y las funciones de begin y end que hacen cosas diferentes a las de los métodos. Creo que tal situación es ideada, mal formada y / o realizada por un programador que no ha tenido mucha experiencia profundizando en el depurador o leyendo errores de la nueva plantilla.