web-dev-qa-db-fra.com

std :: endl est de type inconnu lors de la surcharge de l'opérateur <<

J'ai surchargé l'opérateur <<

template <Typename T>
UIStream& operator<<(const T);

UIStream my_stream;
my_stream << 10 << " heads";

Fonctionne mais:

my_stream << endl;

Donne une erreur de compilation:

erreur C2678: binaire '<<': aucun opérateur trouvé qui prend un opérande de gauche de type 'UIStream' (ou il n'y a pas de conversion acceptable)

Quel est le travail autour de la création de my_stream << endl travail?

56
Kazoom

std::endl est une fonction et std::cout l'utilise en implémentant operator<< pour prendre un pointeur de fonction avec la même signature que std::endl.

Là, il appelle la fonction et transmet la valeur de retour.

Voici un exemple de code:

#include <iostream>

struct MyStream
{
    template <typename T>
    MyStream& operator<<(const T& x)
    {
        std::cout << x;

        return *this;
    }


    // function that takes a custom stream, and returns it
    typedef MyStream& (*MyStreamManipulator)(MyStream&);

    // take in a function with the custom signature
    MyStream& operator<<(MyStreamManipulator manip)
    {
        // call the function, and return it's value
        return manip(*this);
    }

    // define the custom endl for this stream.
    // note how it matches the `MyStreamManipulator`
    // function signature
    static MyStream& endl(MyStream& stream)
    {
        // print a new line
        std::cout << std::endl;

        // do other stuff with the stream
        // std::cout, for example, will flush the stream
        stream << "Called MyStream::endl!" << std::endl;

        return stream;
    }

    // this is the type of std::cout
    typedef std::basic_ostream<char, std::char_traits<char> > CoutType;

    // this is the function signature of std::endl
    typedef CoutType& (*StandardEndLine)(CoutType&);

    // define an operator<< to take in std::endl
    MyStream& operator<<(StandardEndLine manip)
    {
        // call the function, but we cannot return it's value
        manip(std::cout);

        return *this;
    }
};

int main(void)
{
    MyStream stream;

    stream << 10 << " faces.";
    stream << MyStream::endl;
    stream << std::endl;

    return 0;
}

Espérons que cela vous donne une meilleure idée de la façon dont ces choses fonctionnent.

79
GManNickG

J'ai fait ça pour résoudre mon problème, voici une partie de mon code:

    template<typename T> 
    CFileLogger &operator <<(const T value)
    {
        (*this).logFile << value;
        return *this;
    }
    CFileLogger &operator <<(std::ostream& (*os)(std::ostream&))
    {
        (*this).logFile << os;
        return *this;
    }

Main.cpp

int main(){

    CFileLogger log();    
    log << "[WARNINGS] " << 10 << std::endl;
    log << "[ERRORS] " << 2 << std::endl;
    ...
}

J'ai la référence ici http://www.cplusplus.com/forum/general/49590/

J'espère que cela peut aider quelqu'un.

7
Lucas Casagrande

Voir ici pour de meilleures façons d'étendre IOStreams. (Un peu dépassé, et adapté pour VC 6, donc vous devrez le prendre avec un grain de sel)

Le fait est que pour faire fonctionner les foncteurs (et endl, qui produit à la fois "\ n" et flush est un foncteur), vous devez implémenter l'interface ostream complète.

4
EFraim

Les flux std ne sont pas conçus pour être sous-classés car ils n'ont pas de méthodes virtuelles, donc je ne pense pas que vous irez trop loin avec cela. Vous pouvez essayer d'agréger un std :: ostream pour faire le travail.

Pour que endl fonctionne, vous devez implémenter une version de operator<< qui prend un pointeur vers une fonction car c'est ainsi que les manipulateurs tels que endl sont gérés, c'est-à-dire.

UStream& operator<<( UStream&, UStream& (*f)( UStream& ) );

ou

UStream& UStream::operator<<( UStream& (*f)( UStream& ) );

Maintenant std::endl est une fonction qui prend et retourne une référence à un std :: basic_ostream afin que cela ne fonctionne pas directement avec votre flux, vous devrez donc créer votre propre version qui appelle le std::endl version dans votre std::iostream.

Edit: On dirait que la réponse de GMan est meilleure. Il obtient std::endl fonctionne aussi!

3
Troubadour

En plus de la réponse acceptée, avec C++ 11, il est possible de surcharger operator<< pour le type:

decltype(std::endl<char, std::char_traits<char>>)
1
AlwaysLearning