ostream<< in PIMPL



  • Hallo,

    ich frage mich, wie man in einer PIMPL-Idiom-Klasse den ostream Operator implementiert, wenn man ein Template hat.

    Also in der .h:

    class A
    {
        private:
       struct Impl;
            std::unique_ptr<Impl> pImpl;
    };
    

    Und in der .cpp:

    struct Impl
    {
    int i;
    }
    
    A::A()
    : pImpl(std::make_unique<Impl>())) 
    {
       pImpl->i = 20;
    }
    
    template <class _OStream>
        inline _OStream& operator<<(_OStream& os, const A& in_a)
        {
            os << ....  // ???
            return os;
        }
    

    Wir komme ich an die Member ran, wenn ich in der Header nicht auf diese zugreife (auf das i)?



  • Warum ist das ein Tenplate?



  • manni66 schrieb:

    Warum ist das ein Tenplate?

    Na weil ein std::ostream eigentlich ein std::basic_ostream<char> ist. Also die streams sind Templates.
    Man könnte es auch so machen:

    template <class CharType>
        inline std::basic_ostream<CharType> Stream& operator<<(std::basic_ostream<CharType>& os, const A& in_a)
        {
            os << ....  // ???
            return os;
        }
    

    Aber das löst das eigentliche Problem nicht. Ich fürchte, es geht nicht, ohne die Impl bekannt zu machen. Oder Du implementierst den Operator nur für char und wchar_t. Dann kannst Du die Implementierung wieder in die cpp stecken.



  • Es braucht sowieso nur die std::ostream-Überladung, alles andere ist unnötig.

    http://utf8everywhere.org



  • friend std::basic_ostream<char> &operator << (std::basic_ostream<char> &out, A const &a);
    friend std::basic_ostream<char32_t> &operator << (std::basic_ostream<char32_t> &out, A const &a);
    


  • Hallo Stefan,

    wenn Du Impl public machst, gibst Du keine Informationen raus, da Du Impl weiterhin einfach in .cpp definieren kannst. Ich finde es eigentlich ungewöhnlich operator<< immer als friend zu deklarieren. Einfach ein forwarding an eine öffentliche Funktion ergibt die gewünschte Syntax:

    class A
    {
    public:
       struct Impl;
    private:
       std::unique_ptr<Impl> pImpl;
    };
    
    std::ostream& operator<<( std::ostream&, const A& );
    

    .cpp

    class A::Impl 
    {
    public:
       void print( std::ostream& ) const;
    };
    
    std::ostream& operator<<( std::ostream& out, const A& a )
    {
       a.print( out );
       return out;
    }
    

    Wenn operator<<() aber unbedingt ein template sein muss, dann kommst Du wohl nicht darum herum, Impl im header zu definieren. Es sei den, die Liste der Instanziierungen ist übersichtlich, bekannt und klein; dann könntest Du das template auch in .cpp definieren und explizit instanzieren.

    Kleiner Hinweis noch: Bezeichner, die mit einem _ anfangen, gefolgt von einem Großbuchstaben, sind für die Implementierung reserviert. Du dürftest Dich also nicht beschweren, wenn irgend eine Standardlibrary _OStream als Makro definiert.

    mfg Torsten


Anmelden zum Antworten