2015-11-05 1 views
1

Nous savons que endl est manipulateur et interne il met '\n' à tampon, puis rincer le tampon. Où est défini endl? Quel est endl, est-ce macro ou fonction ou variable ou classe ou objet? Comment puis-je définir mon propre manipulateur endl?Où est défini manipulateur endl

+0

L'en-tête 'std :: manipulateur endl' est défini dans' '. – 101010

+0

dans la définition de endl, il semble que c'est fonction alors pourquoi nous ne transmettons aucun argument lorsque nous l'utilisons avec le modèle Cout std :: basic_ostream & endl (std :: basic_ostream & os); –

+0

J'ai essayé de clarifier la question, je pense qu'il ya une bonne question ici et il a attiré une excellente réponse de Yakk. –

Répondre

13

std::endl est un modèle de fonction de la signature:

template<class CharT, class Traits> 
std::basic_ostream<CharT,Traits>& endl(std::basic_ostream<CharT,Traits>&); 

La surcharge std::basic_ostream::operator<<std::basic_ostream<CharT,Traits>>::operator<<(std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&)) accepte une fonction d'une certaine signature.

Lorsque vous faites std::cout << std::endl, la résolution de surcharge est effectuée sur std::endl, qui détermine les types de modèles appropriés pour std::endl et instancie une fonction. Cela se décompose alors en pointeur et est passé à operator<<.

std::basic_ostream::operator<< appelle ensuite la fonction sur le flux d'insertion en question et renvoie la valeur de retour. Quelque chose comme:

template<class CharT, class Traits> 
std::basic_ostream<CharT, Traits>& 
std::basic_ostream<CharT, Traits>::operator<<(
    std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) 
) { 
    return func(*this); 
} 

Mais la mise en œuvre exacte est à la bibliothèque du compilateur écrivain .

std::endl provoque l'impression d'une nouvelle ligne, puis demande à l'ostream de se vider. Vous pouvez Emuler faire std::cout << std::endl; par ces deux lignes de code:

std::cout.put(std::cout.widen('\n')); 
std::cout.flush(); 

Comment exactement std::endl est mis en œuvre appartient au compilateur, mais ce qui précède est une bonne approximation de la façon dont vous pouvez l'écrire (naturellement sur un cours d'eau générique) . Nous vous garantissons avoir accès à std::endl si vous #include <ostream> Vous pouvez y avoir accès si vous incluez un autre fichier d'en-tête de la bibliothèque std. Quel fichier définit exactement est encore à la mise en œuvre.

std::endl est connu sous le nom de "manipulateur io". Cette technique est destinée à permettre à des fonctions qui manipulent l'état du flux io d'être configurées "en ligne" avec des commandes de sortie en enchaînant les appels <<.

Pour créer le vôtre, si vous voulez qu'il fonctionne avec un seul type de ostream, créez simplement une fonction qui prend ce type de ostream par référence, et le renvoie par référence. C'est maintenant un manipulateur de io.

Si vous voulez gérer un ensemble de flux, créez un modèle comme:

template<class CharT, class Traits> 
std::basic_ostream<CharT, Traits>& bob(std::basic_ostream<CharT, Traits>& os) 
{ 
    return os << os.widen('b') << os.widen('o') << os.widen('b'); 
} 

qui est maintenant un manipulateur io qui imprime "bob". Il peut faire ce que vous voulez basic_ostream en question.

Un autre plan est le suivant:

struct bob_t { 
    template<class OS> 
    OS& operator()(OS& os)const { 
    return os << os.widen('b') << os.widen('o') << os.widen('b'); 
    } 
    template<class OS> 
    operator OS&(*)(OS&)() const { 
    return [](OS& os)->OS&{ return bob_t{}(os); }; 
    } 
}; 
static const bob_t bob; 

bob est maintenant un objet qui peut être utilisé comme un manipulateur io.


<< Cette surcharge est une fonction de type A->(A->A)->A. Fondamentalement, au lieu de passer de X à f, on passe X et f à <<, ce qui fait alors f(X). Sucre syntactique pur.

Le fait que std::endl est un modèle signifie que le transfert parfait, il est un peu d'une douleur due à cette technique. Je finis par définir la fonction sans état endl_t types, avec une surcharge operator basic_ostream<CharT,Traits>&(*)(basic_ostream<CharT,Traits>&)()const, donc je peux passer l'ensemble de surcharge par procuration de transfert parfait parfois.

Ensuite, nous pouvons passer l'ensemble de surcharge complet de f:(A->A) à <<, et ont la "couche suivante vers le bas" résoudre la surcharge.

+1

Ceci est une réponse tout à fait impressionnante, ne sais pas pourquoi ce n'est pas la réponse acceptée. –

+0

droit Shafik Yaghmour , désolé d'être trop tard / –

3

http://en.cppreference.com/w/cpp/io/manip/endl dit:

en-tête Defined <ostream>

template< class CharT, class Traits > 
std::basic_ostream<CharT, Traits>& endl(std::basic_ostream<CharT, Traits>& os); 

si je veux coder mon propre manipulateur endl ce code que je dois écrire?

Si vous voulez créer seulement pour std::ostream il suffit de créer une fonction qui accepte référence à std::ostream et retourne un. Si vous voulez le rendre générique, vous pouvez le faire templier, comme std::endl.

+0

il semble que c'est la fonction et si elle est alors pourquoi nous ne sommes pas passer tout argument à lui? –

+0

@NiravsinhParmar becase il est fait à l'intérieur de l'opérateur surchargé '' << qui accepte une fonction de signature certaine. – Slava