Kollision von << für Vector mit Boost::Variant



  • Hallo,

    ich habe einen Ausgabe-Operator für Vector geschrieben

    template<class T> std::ostream& operator<<(std::ostream& s, const std::vector<T>& v)
    {
    	for (typename std::vector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
    		s << *it << " ";
    	return s;
    }
    

    der sich im Namespace IO befindet.

    In einem meiner Source-Dateien kommt es nun bei Verwendung des Operators zu einer Kollision mit dem, was is Boost::Variant definiert ist. So führt

    vector<unsigned> s = IO::size(LSPs);
    	cout << s << endl;
    	IO::operator<<(cout, s) << endl;
    

    zur Fehlermeldung

    ../src/node/rev/nd_creation.cpp: In member function ‘void Node::Prob_Nd::set_anc_LSPs(boost::multi_array<gsl_matrix*, 2ul, std::allocator<gsl_matrix*> >)’:
    ../src/node/rev/nd_creation.cpp:99: error: no match for ‘operator<<’ in ‘std::cout << s’
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:108: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>& (*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:117: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:127: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:165: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:169: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:173: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/ostream.tcc:91: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:180: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/ostream.tcc:105: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:191: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:200: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:204: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:209: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:213: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:221: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/ostream:225: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/ostream.tcc:119: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_streambuf<_CharT, _Traits>*) [with _CharT = char, _Traits = std::char_traits<char>]
    /home/atlas12/ingo/workspace/Gen_Recon/src/node/alphabet.h:40: note:                 std::ostream& Node::operator<<(std::ostream&, const Node::Alphabet&)
    ../src/node/rev/rev_nd.h:150: note:                 std::ostream& Node::operator<<(std::ostream&, const Node::Rev_Nd&)
    make: *** [src/node/rev/nd_creation.o] Error 1
    

    bezüglich der zweiten Zeile, während die dritte fehlerlos kompiliert wird.

    Daher die Frage: Muss ich da einen Workaround wie in der dritten Zeile machen oder gibt es da bessere Alternativen? Kein

    using namespace boost;
    

    zu verwenden würde in diesem Fall zu aufwendig sein.


  • Mod

    template<class T> std::ostream& operator<<(std::ostream& s, const std::vector<T>& v)
    {
        for (typename std::vector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
            s << *it << " ";
        return s;
    }
    

    ➡

    template<class T> std::ostream& operator<<(std::ostream& s, const std::vector<T>& v)
    {
        std::copy( std::begin(v), std::end(v), std::ostream_iterator<T>{s, " "} );
        return s;
    }
    

    Es dürfte doch offensichtlich sein, dass ADL nicht im Namensraum IO nachsieht. Also entweder machst du den bekannt, oder du rufst explizit die Operatorfunktion auf.

    Oder du überlädst den Operator außerhalb von IO. Wobei das ja irgendein Problem zu verursachen scheint.


  • Mod

    Moment mal, was hat Boost.Variant mit std::vector zu tun?

    In einem meiner Source-Dateien kommt es nun bei Verwendung des Operators zu einer Kollision mit dem, was is Boost::Variant definiert ist.

    Wieso sollte Boost.Variant den Ausgabeoperator für vector definieren?



    • schrieb:
    template<class T> std::ostream& operator<<(std::ostream& s, const std::vector<T>& v)
    {
        for (typename std::vector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
            s << *it << " ";
        return s;
    }
    

    ➡

    template<class T> std::ostream& operator<<(std::ostream& s, const std::vector<T>& v)
    {
        std::copy( std::begin(v), std::end(v), std::ostream_iterator<T>{s, " "} );
        return s;
    }
    

    irrelevant. Und bitte ändere den Namen. * ist nicht höflich.



  • in der Fehlermeldung kommt boost nicht einmal vor.


  • Mod

    Und bitte ändere den Namen. * ist nicht höflich.

    Leute, die Email an Markus ist schon laengst verschickt! Vor Tagen!

    irrelevant.

    War ein Tipp wie man es direkter schreiben kann, ohne eine ellenlange for -Schleife mit const_iterator en.
    Edit: Das war natuerlich fuer C++03, ich habe es aus Versehen mit C++11 gemixt...
    In C++11 wuerde man direct zu einer huebschen Schleife tendieren:

    for( auto const& e : v )
        std::cout << e << ' ';
    

    otze schrieb:

    in der Fehlermeldung kommt boost nicht einmal vor.

    Eben. 👍 Was hat Boost damit zu tun.



  • ingobulla schrieb:

    Hallo,
    ich habe ein[ Problem]

    Hallo ingobulla. Es sieht so aus, als sei das ein Problem, bei dem du noch etwas zum Thema
    Namensauflösung zu lernen hast. Leider hast du kein vollständiges Minimalbeispiel
    gepostet. Bitte versuch dein Problem auf ein vollständiges Minimalbeispiel zu reduzieren.
    Z.B. so etwas:

    namespace s {
      struct vec {};
    }
    
    namespace io {
      void func(s::vec&);
    }
    
    namespace test {
    
    void func(int&);
    
    void test()
    {
        using namespace io;
        s::vec v = {};
        func(v); // findet trotz using-Direktive mein io::func nicht :-(
    }
    
    } // namespace test
    
    int main()
    {
        test::test();
    }
    

    Deine Code-Fragmente sind weit von einem vollständigen Beispiel entfernt, dass man da
    eigentlich fast nichts zu sagen kann.

    Ergänzung:
    Sehr wahrscheinlich hast du hier ein "name hiding" Problem. Dein operator<< kann
    nicht per ADL (argument dependent lookup) gefunden werden, weil er gar nicht in einem
    dem std::vector assoziierten Namensraum (std) deklariert wurde. Eine using-Direktive,
    also using namespace IO; kann dir hier nur bedingt helfen, weil die Namenssuche
    schon vorher abbrechen kann, bevor der Namensraum IO untersucht wird. Das siehst du auch
    in meinem Beispiel. Bevor io durchsucht wird, findet der Compiler test::func und hört
    mit der "normalen" Namenssuche auf. ADL kommt dann zum Einsatz. aber ADL durchsucht hier
    nur noch den Namensraum s . Und da gibt's kein func .

    In meinem Beispiel kann man jetzt die using-Direktive durch eine using-Deklaration ersetzen:
    using io::func; . Allerdings ist das keine Lösung für boost::variant. boost::variant
    weiß nicht, dass zum vector der passende operator<< im Namensraum IO ist. Du benutzt also
    entweder für die Ausgabe einen eigenen Visitor oder wrappst den Vektor in einer eigenen
    Klasse

    template<class T>
    class myvec
    {
      std::vector<T> vec_;
      :::
    };
    

    wobei operator<< in demselben Namensraum deklariert werden muss, damit er per ADL gefunden
    werden kann.


  • Mod

    Bevor io durchsucht wird, findet der Compiler test::func und hört mit der "normalen" Namenssuche auf.

    Und wieso wird io erst nach test durchsucht, obwohl wir doch die using-DeklarationDirektive direkt in der Funktion stehen haben?
    Weil:

    A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive.
    During unqualified name lookup (3.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace.

    Das heißt, func wird vom Namelookup als ein Member des globalen Namensraums behandelt - und es wird ja schließlich zuerst in den innersten und erst dann in den äußeren Scopes gesucht.



  • Arcoth schrieb:

    Bevor io durchsucht wird, findet der Compiler test::func und hört mit der "normalen" Namenssuche auf.

    Und wieso wird io erst nach test durchsucht, obwohl wir doch die using-Deklaration direkt in der Funktion stehen haben?

    Du meintest sicherlich "using-Direktive".

    Anyhow, danke für's Raussuchen und Zitieren.


  • Mod

    Ups, da habe ich mich verschrieben.
    using -Deklaration wäre natürlich etwas a la

    using io::func;
    

    Und das ist gerade, was ja funktioniert.


Anmelden zum Antworten