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