63 votes

std :: endl est de type inconnu lors d'une 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 gauche du type 'UIStream' (ou il n'y a pas de conversion acceptable)

Quelle est la solution pour que my_stream << endl travaille?

88voto

GManNickG Points 155079

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

Dans celui-ci, 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;
}
 

J'espère que cela vous donne une meilleure idée de la façon dont ces choses fonctionnent.

37voto

AProgrammer Points 31212

Le problème est que std::endl est un modèle de fonction, l'opérateur<< est. Donc, lorsque vous écrivez:

my_stream << endl;

vous aimerez le compilateur de déduire les paramètres du modèle pour l'opérateur ainsi que pour endl. Ce n'est pas possible.

Donc, vous avez à écrire d'autres, non du modèle, surcharge de l'opérateur<< pour travailler avec les manipulateurs. Leur prototype va ressembler:

UIStream& operator<<(UIStream& os, std::ostream& (*pf)(std::ostream&));

(il y en a deux autres, en remplacement de std::ostream par std::basic_ios et std::ios_base, que vous avez également à fournir si vous le souhaitez, permet à tous les les manipulateurs) et leur mise en œuvre sera très similaire à celui de votre modèle. En fait, si semblables que vous pouvez utiliser votre modèle pour mise en œuvre comme ceci:

typedef std::ostream& (*ostream_manipulator)(std::ostream&);
UIStream& operator<<(UIStream& os, ostream_manipulator pf)
{
   return operator<< <ostream_manipulator> (os, pf);
}

Une dernière remarque, souvent écrit une coutume streambuf est souvent un meilleur moyen de réaliser ce qu'on essaie de réaliser l'application de la technique que vous utilisez.

4voto

EFraim Points 7137

Voir ici pour de meilleurs moyens d’étendre IOStreams. (Un peu démodé, et adapté pour VC 6, vous devrez donc le prendre avec un grain de sel)

Le fait est que pour que les foncteurs fonctionnent (et qu’ils utilisent endl, "\ n" et que flush est un foncteur), vous devez implémenter l’interface ostream complète.

4voto

Troubadour Points 9485

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

Pour faire endl travail vous avez besoin pour mettre en œuvre une version d' operator<< qui prend un pointeur de fonction qui est de savoir comment les manipulateurs comme endl sont gérées 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 donc qui ne travaillent pas directement avec votre flux de sorte que vous aurez besoin pour faire votre propre version des appels par le biais de l' std::endl version dans votre agrégées std::iostream.

Edit: Regarde aime GMan la réponse est mieux. Il reçoit std::endl travaillent trop!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X