Comment les manipulateurs de stream en C ++ peuvent-ils être des fonctions?

Lors de l’appel d’une fonction en C ++, son nom est écrit suivi de () pour le distinguer en tant qu’appel de fonction. Pourquoi ne puis-je pas appeler les fonctions de manipulation de stream de la même manière?

Pourquoi ce n’est pas permis ?:

 cout << "Hello!" << endl(); 

Est-ce que endl n’est pas une variable tenant \n ?

Merci!

Endl n’est-il pas une variable tenant \ n?

Non ce n’est pas. std::endl est une fonction définie dans un espace de noms global

  template inline basic_ostream<_CharT, _Traits>& endl(basic_ostream<_CharT, _Traits>& __os) { return flush(__os.put(__os.widen('\n'))); } 

Dans l’expression std::cout << endl_or_something droite de << est l'argument d'un appel à l' operator<< (le premier argument est implicitement std::ostream ). Donc, endl_or_something devrait être un type int, double ou autre pouvant être converti en l'un des arguments possibles de l' operator<< . Il existe une version surchargée de cet opérateur qui prend des pointeurs vers des fonctions (fonctions prenant référence à std::ostream et std::ostream référence à std::ostream ):

  // [27.6.2.5] formatted output // [27.6.2.5.3] basic_ostream::operator<< //@{ /** * @brief Interface for manipulators. * * Manipulators such as @c std::endl and @c std::hex use these * functions in constructs like "std::cout << std::endl". For more * information, see the iomanip header. */ __ostream_type& operator<<(__ostream_type& (*__pf)(__ostream_type&)) { // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 60. What is a formatted input function? // The inserters for manipulators are *not* formatted output functions. return __pf(*this); } 

Puisque std::endl signature correspond, il peut être utilisé dans expression

 std::cout << "Hello!" << std::endl; 

ou équivalent

 std::cout << "Hello!"; std::endl( std::cout); 

Notez cependant que ce manipulateur est souvent utilisé à tort quand une nouvelle ligne est souhaitée, ce qui entraîne de mauvaises performances de mise en mémoire tampon. Dans ce cas, utilisez simplement "\n" .


Pourquoi ce n'est pas permis ?:

 cout << "Hello!" << endl(); 

std :: endl prend un argument, std :: ostream. Vous pouvez voir qu'il peut être appelé avec:

 return __pf(*this); 

veux dire

 return std::endl( *this); // std::endl( std::cout); 

Il n’existe pas de version de std::endl qui ne prend aucun paramètre et qui pourrait donc être appelée avec

 std::endl() 

En expression

 std::cout << std::endl; 

il désigne un argument pour l' operator<< , il est passé en tant que pointeur à fonction puis appelé dans le corps de l' operator<< .

Les manipulateurs sont des fonctions spécialement conçues pour être utilisées avec les opérateurs d’insertion (<<) et d'extraction (>>) sur des objects de stream, par exemple:

 cout << boolalpha; 

Ce sont toujours des fonctions normales et peuvent également être appelées comme toute autre fonction utilisant un object de stream comme argument, par exemple:

 boolalpha (cout); 

Donc, dans votre code, vous pouvez faire

 cout << "Hello!"; endl(cout); 

au lieu de

 cout << "Hello!" << endl; 

Source

Les manipulateurs de stream sont des fonctions. En tant que tels, ils peuvent être appelés en utilisant l’opérateur d’appel () . Voici comment appeler std::endl sur un stream:

 std::endl(std::cout); 

C’est ainsi qu’il devrait être appelé pour chaque stream sur lequel vous voulez utiliser std::endl . Cela est dû au fait que std::endl est une fonction qui renvoie une référence à un object de stream. C’est une façon très bizarre de le faire, il existe donc une fonction pratique pour diffuser en ligne la syntaxe:

 std::ostream& operator<<(std::ostream& (*manip)(std::ostream&)); 

Il s'agit d'une surcharge de l' operator<<() qui prend un stream sur son côté gauche et un manipulateur sur son côté droit. std::endl est techniquement une fonction, elle peut donc être convertie en un pointeur de fonction.

Dans la mise en œuvre de cette surcharge, manip est appelé à peu près comment je viens de vous montrer. Cela permet une syntaxe telle que:

 std::cout << "Hello, World" << std::endl; 

Si vous appelez std::endl à l'aide de l'opérateur call, vous renverrez une référence au stream. Il y a une autre surcharge d' operator<<() qui prend un const void* comme argument. Ce sera la surcharge qui est appelée par inadvertance.

 std::cout << std::endl(std::cout); // prints a newline then an address