2015-09-20 19 views
6

Si tratta di un'estensione a questa domanda a partire dal 2011: Range-based for loops and ADLRange-based per Loop e ADL

utilizzando Visual Studio 2015, io non sono in grado di fare una serie basata su ciclo for per un contenitore personalizzato utilizzando Argument Ricerca dipendente (ADL).

ho fatto un semplice caso di test di seguito con un contenitore personalizzato:

#include <vector> 

namespace Foo 
{ 
    template <typename T> 
    class Container 
    { 
    public: 

     std::vector<T> values; 
    }; 
} 

template <typename T> 
typename std::vector<T>::iterator begin(Foo::Container<T>& foo) 
{ 
    return foo.values.begin(); 
} 

template <typename T> 
typename std::vector<T>::iterator end(Foo::Container<T>& foo) 
{ 
    return foo.values.end(); 
} 

Utilizzando questo contenitore e ADL, il seguente test compila perfettamente bene:

int main(int argc, char* argv[]) 
{ 
    Foo::Container<int> values; 

    for (auto it = begin(values); it != end(values); ++it) 
    { 
     ... 
    } 

    return 0; 
} 

come dovrebbe. Non sono sicuro che ADL sia utilizzato anche qui, ma a prescindere, ha senso. Da MSDN documentation, abbiamo:

Tenete a mente questi fatti in merito al campo-base per: array

  • riconosce automaticamente.

  • Riconosce i contenitori con .begin() e .end().

  • Utilizza la ricerca dipendente dall'argomento begin() e end() per qualsiasi altra cosa.

Da quello che ho capito di ADL, e la documentazione di cui sopra, il seguente dovrebbe anche compilare:

int main(int argc, char* argv[]) 
{ 
    Foo::Container<int> values; 

    for (auto value : values) 
    { 
     ... 
    } 

    return 0; 
} 

Ma non è così. Invece, ottengo i seguenti errori:

error C3312: no callable 'begin' function found for type 'Foo::Container<int>' 
error C3312: no callable 'end' function found for type 'Foo::Container<int>' 

Allora, che succede qui? La mia interpretazione di ADL è errata o si tratta di un bug con il compilatore MSVC 14.0?

+1

IINM 'begin()' e 'end()' dovrebbe trovarsi in 'Foo'. – Quentin

+0

Questo non dipende da ADL poiché 'begin' e' end' non si trovano nello spazio dei nomi 'Foo', ma sembra funzionare bene in gcc: http://coliru.stacked-crooked.com/a/12047609140d05a9. Se cambi 'begin' e' end' per prendere invece un 'const' ref, funziona su MSVC? – rici

+0

@rici, no, non è così. Mi chiedo perché funzioni in GCC anche se la risposta di Pavlo è giusta. Quale compilatore è quello giusto ?!:) – Zeenobit

risposta

7

È necessario posizionare sia begin e end nello spazio dei nomi per ADL per funzionare. Questo perché ADL esaminerà gli spazi dei nomi degli argomenti corrispondenti alle definizioni di ricerca di begin e end.

namespace Foo 
{ 
    template <typename T> 
    class Container 
    { 
    public: 

     std::vector<T> values; 
    }; 

    template <typename T> 
    typename std::vector<T>::iterator begin(Foo::Container<T>& foo) 
    { 
     return foo.values.begin(); 
    } 

    template <typename T> 
    typename std::vector<T>::iterator end(Foo::Container<T>& foo) 
    { 
     return foo.values.end(); 
    } 
} 

UPD: Il motivo per cui begin e end dal namespace globale non sono considerati è a causa dello standard aggiornato dicendo che begin e end sono guardato in spazi dei nomi associati ma ordinaria unquali ricerca fi cato non viene eseguita. Questa è una conseguenza della correzione di errori nello standard (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1442).

+0

Dovrebbe funzionare anche con 'begin' e' end' definiti nello spazio dei nomi globale. Perché no? – rici

+0

@rici questo perché la normale ricerca non qualificata (ricerca nello spazio dei nomi globale) non viene eseguita secondo lo standard aggiornato: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1442 –

+0

@PavloMur Grazie per il chiarimento. – Zeenobit