2012-06-28 11 views
8

Al iterar sobre un contenedor estándar, ¿cree que es una buena idea omitir el prefijo std:: y confiar en ADL para encontrar la definición? Ejemplo:Confiando en ADL para std :: begin() y std :: end()?

std::vector<int> vec = get_vec(); 
// range-based for loop would be preferred here, but just for the sake of example 
for (auto it = begin(vec), end = end(vec); it != end; ++it) { /*...*/ } 

¿Hay alguna razón para hacer o no hacer esto?

+1

¿Qué hay de malo con '.begin()' y '.end()' (que, FYI, ¿qué base de rango se usa aquí, no 'std :: begin' y' std :: end')? –

+1

No tengo nada en contra. Sin embargo, recuerdo una diapositiva de Herb Setter que nos dice que preferimos las funciones gratuitas sobre las funciones de inicio/final de miembro. – StackedCrooked

+6

@ R.MartinhoFernandes: Porque std :: begin() y std :: end() funcionan en matrices (así como en contenedores estándar (u otros objetos para los que ha escrito especializaciones)). Por lo tanto, puede cambiar el tipo subyacente de un vector sin tener que modificar ningún otro código. –

Respuesta

13

Si va a utilizar ADL para poder cambiar el tipo de contenedor sin cambiar los bucles, agregue using std::begin; using std::end;. Eso asegura que encuentre las funciones std para contenedores de otros espacios de nombres que tengan miembros begin y end, pero no funciones gratuitas en su espacio de nombres.

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 
+0

Creo que incluso sería mejor volver a abrir 'namespace my', y agregar funciones que no sean miembros' begin() 'y' end() 'para' container'. Esto incluso funciona para el código heredado (porque los espacios de nombres están abiertos). También le permite eliminar las declaraciones 'using' para' std :: begin() 'y' std :: end', que son difíciles de usar en el código de solo encabezado. – TemplateRex

+1

Creo que es una práctica bastante mala volver a abrir espacios de nombres de código heredado o de terceros. 'begin()' y 'end()' son invocaciones de función, por lo tanto, lo más probable es que estén en el nivel de función. La directiva 'using' puede colocarse en el mismo nivel (función) (ver, por ejemplo, la respuesta de Nawaz), lo que da como resultado cero efectos secundarios. – misberner

8

qué cree que es una buena idea para omitir el prefijo y std :: depender de ADL para encontrar la definición?

Creo que es una buena idea. Se hace necesario en las plantillas como esto:

template<typename Container> 
void do_work(Container const & c) 
{ 
    using std::begin; //enable ADL 
    using std::end; //enable ADL 

    //now let compiler search the correct begin/end in the initialization part 
    for(auto it = begin(c), itend = end(c); it != itend ; ++it) 
    { 
     //do work 
    } 
} 

Aquí desde Container puede ser un tipo definido por el programador, por ejemplo en espacio de nombres xyz, entonces, ¿cómo sería el trabajo de la plantilla función anterior si escribo std::begin en lugar de sólo begin (en la parte de inicialización)?

Cuestiones relacionadas