Bonjour la liste,
Je n'arrive pas à saisir le concept des « rvalue references », promis
pour la prochaine normalisation du C++.
À quoi cela correspond-t-il concrètement ? Quelle en est l'utilité
pratique ?
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html>
Merci pour vos éclaircissements.
Bonjour la liste,
Je n'arrive pas à saisir le concept des « rvalue references », promis
pour la prochaine normalisation du C++.
À quoi cela correspond-t-il concrètement ? Quelle en est l'utilité
pratique ?
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html>
Merci pour vos éclaircissements.
Bonjour la liste,
Je n'arrive pas à saisir le concept des « rvalue references », promis
pour la prochaine normalisation du C++.
À quoi cela correspond-t-il concrètement ? Quelle en est l'utilité
pratique ?
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html>
Merci pour vos éclaircissements.
Bonjour la liste,
Je n'arrive pas à saisir le concept des « rvalue references », promis
pour la prochaine normalisation du C++.
2. Utilisation de temporaires en tant que paramètre non const.
Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
une fonction en tant que paramètre non-const (Pour peu que la class soit
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.
logstream get_log_stream();
Aujourdhui, tu ne peux pas faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
Bonjour la liste,
Je n'arrive pas à saisir le concept des « rvalue references », promis
pour la prochaine normalisation du C++.
2. Utilisation de temporaires en tant que paramètre non const.
Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
une fonction en tant que paramètre non-const (Pour peu que la class soit
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.
logstream get_log_stream();
Aujourdhui, tu ne peux pas faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
Bonjour la liste,
Je n'arrive pas à saisir le concept des « rvalue references », promis
pour la prochaine normalisation du C++.
2. Utilisation de temporaires en tant que paramètre non const.
Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
une fonction en tant que paramètre non-const (Pour peu que la class soit
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.
logstream get_log_stream();
Aujourdhui, tu ne peux pas faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
Bonjour la liste,
Je n'arrive pas à saisir le concept des « rvalue references », promis
pour la prochaine normalisation du C++.
2. Utilisation de temporaires en tant que paramètre non const.
Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée p ar
une fonction en tant que paramètre non-const (Pour peu que la class so it
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.
logstream get_log_stream();
Aujourdhui, tu ne peux pas faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
En fait si, tu peux le faire, a condition que get_log_stream renvoie
un proxy copiable, avec un comptage de reference et un operator<<
template qui prend en premier argument un const :
template< typename T >
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest, T const& src )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
Au passage: merci James.
Mais c'est vrai qu'avec le move, c'est beaucoup plus simple, puisque
tout le bazar necessaire jusqu'a present sera offert par le langage.
Bonjour la liste,
Je n'arrive pas à saisir le concept des « rvalue references », promis
pour la prochaine normalisation du C++.
2. Utilisation de temporaires en tant que paramètre non const.
Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée p ar
une fonction en tant que paramètre non-const (Pour peu que la class so it
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.
logstream get_log_stream();
Aujourdhui, tu ne peux pas faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
En fait si, tu peux le faire, a condition que get_log_stream renvoie
un proxy copiable, avec un comptage de reference et un operator<<
template qui prend en premier argument un const :
template< typename T >
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest, T const& src )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
Au passage: merci James.
Mais c'est vrai qu'avec le move, c'est beaucoup plus simple, puisque
tout le bazar necessaire jusqu'a present sera offert par le langage.
Bonjour la liste,
Je n'arrive pas à saisir le concept des « rvalue references », promis
pour la prochaine normalisation du C++.
2. Utilisation de temporaires en tant que paramètre non const.
Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée p ar
une fonction en tant que paramètre non-const (Pour peu que la class so it
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.
logstream get_log_stream();
Aujourdhui, tu ne peux pas faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
En fait si, tu peux le faire, a condition que get_log_stream renvoie
un proxy copiable, avec un comptage de reference et un operator<<
template qui prend en premier argument un const :
template< typename T >
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest, T const& src )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
Au passage: merci James.
Mais c'est vrai qu'avec le move, c'est beaucoup plus simple, puisque
tout le bazar necessaire jusqu'a present sera offert par le langage.
On 20 mar, 10:34, Michel Decima wrote:En fait si, tu peux le faire, a condition que get_log_stream renvoie
un proxy copiable, avec un comptage de reference et un operator<<
template qui prend en premier argument un const :
template< typename T >
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest, T const& src )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
Une remarque pour dire qu'il y a une petite subtilité. J'ai déjà du le
faire et ça ne fonctionnait pas parfaitement, bizarrement les
manipulateurs passaient mal. Il faut aussi rajouter 2 ou 3 méthodes
définies dans std::iostream (ou une classe de base) en plus d'un
opérateur << généraliste (ça fait un bout de temps, je ne me souviens
plus lesquelles ni comment j'avais déduit qu'il fallait les définir,
mais je me souviens que j'avais bien galèré).
On 20 mar, 10:34, Michel Decima <michel.dec...@orange-ft.com> wrote:
En fait si, tu peux le faire, a condition que get_log_stream renvoie
un proxy copiable, avec un comptage de reference et un operator<<
template qui prend en premier argument un const :
template< typename T >
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest, T const& src )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
Une remarque pour dire qu'il y a une petite subtilité. J'ai déjà du le
faire et ça ne fonctionnait pas parfaitement, bizarrement les
manipulateurs passaient mal. Il faut aussi rajouter 2 ou 3 méthodes
définies dans std::iostream (ou une classe de base) en plus d'un
opérateur << généraliste (ça fait un bout de temps, je ne me souviens
plus lesquelles ni comment j'avais déduit qu'il fallait les définir,
mais je me souviens que j'avais bien galèré).
On 20 mar, 10:34, Michel Decima wrote:En fait si, tu peux le faire, a condition que get_log_stream renvoie
un proxy copiable, avec un comptage de reference et un operator<<
template qui prend en premier argument un const :
template< typename T >
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest, T const& src )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
Une remarque pour dire qu'il y a une petite subtilité. J'ai déjà du le
faire et ça ne fonctionnait pas parfaitement, bizarrement les
manipulateurs passaient mal. Il faut aussi rajouter 2 ou 3 méthodes
définies dans std::iostream (ou une classe de base) en plus d'un
opérateur << généraliste (ça fait un bout de temps, je ne me souviens
plus lesquelles ni comment j'avais déduit qu'il fallait les définir,
mais je me souviens que j'avais bien galèré).
je viens de refaire le test, et j'ai bien l'impression que le premier est
inutile (std::hex peut passer par la version generique) alors que
le second est necessaire pour std::endl... bizarre.
je viens de refaire le test, et j'ai bien l'impression que le premier est
inutile (std::hex peut passer par la version generique) alors que
le second est necessaire pour std::endl... bizarre.
je viens de refaire le test, et j'ai bien l'impression que le premier est
inutile (std::hex peut passer par la version generique) alors que
le second est necessaire pour std::endl... bizarre.
Michel Decima writes:je viens de refaire le test, et j'ai bien l'impression que le premier est
inutile (std::hex peut passer par la version generique) alors que
le second est necessaire pour std::endl... bizarre.
std::hex n'est pas template, std::endl l'est. Ce doit etre une histoire de
deductibilite de parametres templates.
Michel Decima <michel.decima@wanadoo.fr> writes:
je viens de refaire le test, et j'ai bien l'impression que le premier est
inutile (std::hex peut passer par la version generique) alors que
le second est necessaire pour std::endl... bizarre.
std::hex n'est pas template, std::endl l'est. Ce doit etre une histoire de
deductibilite de parametres templates.
Michel Decima writes:je viens de refaire le test, et j'ai bien l'impression que le premier est
inutile (std::hex peut passer par la version generique) alors que
le second est necessaire pour std::endl... bizarre.
std::hex n'est pas template, std::endl l'est. Ce doit etre une histoire de
deductibilite de parametres templates.
1. la sémantique de déplacement (move semantic).
C'est à dire par exemple qu'au lieu de copier un objet puis de détruir e
l'ancien, tu peux directement transférer l'objet à un autre endroit de
la mémoire.
C'est intéressant pour les swap par example où tu n'est plus obligé
d'appeler 1 constructeur par copie et deux opérateur par copie, tu fais
juste un move comme tu le ferais avec un memcpy pour des POD.
C'est aussi intéressant pour les ressources qui ne doivent pas être
dupliquées comme les mutex. C'est en fait une autre application de swap
(sans spécialisation requise). Ou encore pour faire la distinction entre
une copy où la ressource doit être dupliquée ou peut rester partag ée
(comptage de référence).
2. Utilisation de temporaires en tant que paramètre non const.
Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
une fonction en tant que paramètre non-const (Pour peu que la class soit
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.
logstream get_log_stream();
Aujourdhui, tu ne peux pas faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
Parce que les fonctions de stream sont de la forme:
template<typename T>
ostream& operator<<(ostream& os, const T& t)
{
// ...
return os;
}
Et donc tu ne peux pas mettre une temporaire en paramètre 'os' car il
n'est pas const.
1. la sémantique de déplacement (move semantic).
C'est à dire par exemple qu'au lieu de copier un objet puis de détruir e
l'ancien, tu peux directement transférer l'objet à un autre endroit de
la mémoire.
C'est intéressant pour les swap par example où tu n'est plus obligé
d'appeler 1 constructeur par copie et deux opérateur par copie, tu fais
juste un move comme tu le ferais avec un memcpy pour des POD.
C'est aussi intéressant pour les ressources qui ne doivent pas être
dupliquées comme les mutex. C'est en fait une autre application de swap
(sans spécialisation requise). Ou encore pour faire la distinction entre
une copy où la ressource doit être dupliquée ou peut rester partag ée
(comptage de référence).
2. Utilisation de temporaires en tant que paramètre non const.
Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
une fonction en tant que paramètre non-const (Pour peu que la class soit
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.
logstream get_log_stream();
Aujourdhui, tu ne peux pas faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
Parce que les fonctions de stream sont de la forme:
template<typename T>
ostream& operator<<(ostream& os, const T& t)
{
// ...
return os;
}
Et donc tu ne peux pas mettre une temporaire en paramètre 'os' car il
n'est pas const.
1. la sémantique de déplacement (move semantic).
C'est à dire par exemple qu'au lieu de copier un objet puis de détruir e
l'ancien, tu peux directement transférer l'objet à un autre endroit de
la mémoire.
C'est intéressant pour les swap par example où tu n'est plus obligé
d'appeler 1 constructeur par copie et deux opérateur par copie, tu fais
juste un move comme tu le ferais avec un memcpy pour des POD.
C'est aussi intéressant pour les ressources qui ne doivent pas être
dupliquées comme les mutex. C'est en fait une autre application de swap
(sans spécialisation requise). Ou encore pour faire la distinction entre
une copy où la ressource doit être dupliquée ou peut rester partag ée
(comptage de référence).
2. Utilisation de temporaires en tant que paramètre non const.
Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
une fonction en tant que paramètre non-const (Pour peu que la class soit
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.
logstream get_log_stream();
Aujourdhui, tu ne peux pas faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
Parce que les fonctions de stream sont de la forme:
template<typename T>
ostream& operator<<(ostream& os, const T& t)
{
// ...
return os;
}
Et donc tu ne peux pas mettre une temporaire en paramètre 'os' car il
n'est pas const.
On 20 mar, 10:34, Michel Decima wrote:En fait si, tu peux le faire, a condition que
get_log_stream renvoie un proxy copiable, avec un comptage
de reference et un operator<< template qui prend en premier
argument un const :
template< typename T >
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest, T const& src )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
Une remarque pour dire qu'il y a une petite subtilité. J'ai
déjà du le faire et ça ne fonctionnait pas parfaitement,
bizarrement les manipulateurs passaient mal. Il faut aussi
rajouter 2 ou 3 méthodes définies dans std::iostream (ou une
classe de base) en plus d'un opérateur << généraliste (ça
fait un bout de temps, je ne me souviens plus lesquelles ni
comment j'avais déduit qu'il fallait les définir, mais je me
souviens que j'avais bien galèré).
Effectivement, ca ne suffit pas, je n'avais pas tout dit. Pour
les manipulateurs sous forme de pointeurs de fonctions (ie
ceux qui ne sont pas dans <iomanip>) il faudra ajouter deux
operateurs :
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest,
std::ios_base& ( *src )( std::ios_base& ) )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest,
std::ostream& ( *src )( std::ostream& ) )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
je viens de refaire le test, et j'ai bien l'impression que le
premier est inutile (std::hex peut passer par la version
generique) alors que le second est necessaire pour
std::endl... bizarre.
On 20 mar, 10:34, Michel Decima <michel.dec...@orange-ft.com> wrote:
En fait si, tu peux le faire, a condition que
get_log_stream renvoie un proxy copiable, avec un comptage
de reference et un operator<< template qui prend en premier
argument un const :
template< typename T >
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest, T const& src )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
Une remarque pour dire qu'il y a une petite subtilité. J'ai
déjà du le faire et ça ne fonctionnait pas parfaitement,
bizarrement les manipulateurs passaient mal. Il faut aussi
rajouter 2 ou 3 méthodes définies dans std::iostream (ou une
classe de base) en plus d'un opérateur << généraliste (ça
fait un bout de temps, je ne me souviens plus lesquelles ni
comment j'avais déduit qu'il fallait les définir, mais je me
souviens que j'avais bien galèré).
Effectivement, ca ne suffit pas, je n'avais pas tout dit. Pour
les manipulateurs sous forme de pointeurs de fonctions (ie
ceux qui ne sont pas dans <iomanip>) il faudra ajouter deux
operateurs :
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest,
std::ios_base& ( *src )( std::ios_base& ) )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest,
std::ostream& ( *src )( std::ostream& ) )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
je viens de refaire le test, et j'ai bien l'impression que le
premier est inutile (std::hex peut passer par la version
generique) alors que le second est necessaire pour
std::endl... bizarre.
On 20 mar, 10:34, Michel Decima wrote:En fait si, tu peux le faire, a condition que
get_log_stream renvoie un proxy copiable, avec un comptage
de reference et un operator<< template qui prend en premier
argument un const :
template< typename T >
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest, T const& src )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
Une remarque pour dire qu'il y a une petite subtilité. J'ai
déjà du le faire et ça ne fonctionnait pas parfaitement,
bizarrement les manipulateurs passaient mal. Il faut aussi
rajouter 2 ou 3 méthodes définies dans std::iostream (ou une
classe de base) en plus d'un opérateur << généraliste (ça
fait un bout de temps, je ne me souviens plus lesquelles ni
comment j'avais déduit qu'il fallait les définir, mais je me
souviens que j'avais bien galèré).
Effectivement, ca ne suffit pas, je n'avais pas tout dit. Pour
les manipulateurs sous forme de pointeurs de fonctions (ie
ceux qui ne sont pas dans <iomanip>) il faudra ajouter deux
operateurs :
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest,
std::ios_base& ( *src )( std::ios_base& ) )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
inline OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest,
std::ostream& ( *src )( std::ostream& ) )
{
if ( std::ostream* target = dest.getStream() ) {
*target << src;
}
return dest;
}
je viens de refaire le test, et j'ai bien l'impression que le
premier est inutile (std::hex peut passer par la version
generique) alors que le second est necessaire pour
std::endl... bizarre.
Bonjour,1. la sémantique de déplacement (move semantic).
C'est à dire par exemple qu'au lieu de copier un objet puis de détruire
l'ancien, tu peux directement transférer l'objet à un autre endroit de
la mémoire.
C'est intéressant pour les swap par example où tu n'est plus obligé
d'appeler 1 constructeur par copie et deux opérateur par copie, tu fais
juste un move comme tu le ferais avec un memcpy pour des POD.
C'est aussi intéressant pour les ressources qui ne doivent pas être
dupliquées comme les mutex. C'est en fait une autre application de swap
(sans spécialisation requise). Ou encore pour faire la distinction entre
une copy où la ressource doit être dupliquée ou peut rester partagée
(comptage de référence).
pas de problème pour comprendre que vaut la source :
struct Pouet {... };
Pouet p1;
..
..
.
Pouet && p2 = p1; //
// Quelle valeur prend p1 ?2. Utilisation de temporaires en tant que paramètre non const.
Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
une fonction en tant que paramètre non-const (Pour peu que la class soit
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.
logstream get_log_stream();
Aujourdhui, tu ne peux pas faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
Parce que les fonctions de stream sont de la forme:
template<typename T>
ostream& operator<<(ostream& os, const T& t)
{
// ...
return os;
}
Et donc tu ne peux pas mettre une temporaire en paramètre 'os' car il
n'est pas const.
Je ne comprends pas trop pk cela ne compile pas :
class Pouet
{
public:
Pouet(void)
{
std::cout << "Pouet(void) this=" << this << std::endl;
}
~Pouet(void)
{
std::cout << "~Pouet(void) this=" << this << std::endl;
}
template <class T> Pouet& print(const T&t)
{
std::cout << "print(const T&t) t=" << t << std::endl;
return *this;
}
};
template<class T>
Pouet & operator<<(Pouet & p, const T & t)
{
p.print(t);
return p;
}
Pouet get_truc(void)
{
Pouet p;
return p;
}
//
// La ligne suivant ne compile pas oki
get_truc() << "Bllla bllaaa" << 5 << " truc";
//
// Par contre la ligne suivant compile
get_truc().print("Bllla bllaaa").print(5).print("truc");
Pourquoi la seconde ligne compile ?
Bonjour,
1. la sémantique de déplacement (move semantic).
C'est à dire par exemple qu'au lieu de copier un objet puis de détruire
l'ancien, tu peux directement transférer l'objet à un autre endroit de
la mémoire.
C'est intéressant pour les swap par example où tu n'est plus obligé
d'appeler 1 constructeur par copie et deux opérateur par copie, tu fais
juste un move comme tu le ferais avec un memcpy pour des POD.
C'est aussi intéressant pour les ressources qui ne doivent pas être
dupliquées comme les mutex. C'est en fait une autre application de swap
(sans spécialisation requise). Ou encore pour faire la distinction entre
une copy où la ressource doit être dupliquée ou peut rester partagée
(comptage de référence).
pas de problème pour comprendre que vaut la source :
struct Pouet {... };
Pouet p1;
..
..
.
Pouet && p2 = p1; //
// Quelle valeur prend p1 ?
2. Utilisation de temporaires en tant que paramètre non const.
Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
une fonction en tant que paramètre non-const (Pour peu que la class soit
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.
logstream get_log_stream();
Aujourdhui, tu ne peux pas faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
Parce que les fonctions de stream sont de la forme:
template<typename T>
ostream& operator<<(ostream& os, const T& t)
{
// ...
return os;
}
Et donc tu ne peux pas mettre une temporaire en paramètre 'os' car il
n'est pas const.
Je ne comprends pas trop pk cela ne compile pas :
class Pouet
{
public:
Pouet(void)
{
std::cout << "Pouet(void) this=" << this << std::endl;
}
~Pouet(void)
{
std::cout << "~Pouet(void) this=" << this << std::endl;
}
template <class T> Pouet& print(const T&t)
{
std::cout << "print(const T&t) t=" << t << std::endl;
return *this;
}
};
template<class T>
Pouet & operator<<(Pouet & p, const T & t)
{
p.print(t);
return p;
}
Pouet get_truc(void)
{
Pouet p;
return p;
}
//
// La ligne suivant ne compile pas oki
get_truc() << "Bllla bllaaa" << 5 << " truc";
//
// Par contre la ligne suivant compile
get_truc().print("Bllla bllaaa").print(5).print("truc");
Pourquoi la seconde ligne compile ?
Bonjour,1. la sémantique de déplacement (move semantic).
C'est à dire par exemple qu'au lieu de copier un objet puis de détruire
l'ancien, tu peux directement transférer l'objet à un autre endroit de
la mémoire.
C'est intéressant pour les swap par example où tu n'est plus obligé
d'appeler 1 constructeur par copie et deux opérateur par copie, tu fais
juste un move comme tu le ferais avec un memcpy pour des POD.
C'est aussi intéressant pour les ressources qui ne doivent pas être
dupliquées comme les mutex. C'est en fait une autre application de swap
(sans spécialisation requise). Ou encore pour faire la distinction entre
une copy où la ressource doit être dupliquée ou peut rester partagée
(comptage de référence).
pas de problème pour comprendre que vaut la source :
struct Pouet {... };
Pouet p1;
..
..
.
Pouet && p2 = p1; //
// Quelle valeur prend p1 ?2. Utilisation de temporaires en tant que paramètre non const.
Par exemple, ça veut dire que tu peux utiliser une valeur renvoyée par
une fonction en tant que paramètre non-const (Pour peu que la class soit
moveable).Une application pratique est une fonction get_log_stream() qui
te renvoie une stream que tu vas utiliser pour contruire un log; le log
est envoyé à la destruction de la stream.
logstream get_log_stream();
Aujourdhui, tu ne peux pas faire:
get_log_stream()<<"LOG: Error "<<errno<<std::endl;
Parce que les fonctions de stream sont de la forme:
template<typename T>
ostream& operator<<(ostream& os, const T& t)
{
// ...
return os;
}
Et donc tu ne peux pas mettre une temporaire en paramètre 'os' car il
n'est pas const.
Je ne comprends pas trop pk cela ne compile pas :
class Pouet
{
public:
Pouet(void)
{
std::cout << "Pouet(void) this=" << this << std::endl;
}
~Pouet(void)
{
std::cout << "~Pouet(void) this=" << this << std::endl;
}
template <class T> Pouet& print(const T&t)
{
std::cout << "print(const T&t) t=" << t << std::endl;
return *this;
}
};
template<class T>
Pouet & operator<<(Pouet & p, const T & t)
{
p.print(t);
return p;
}
Pouet get_truc(void)
{
Pouet p;
return p;
}
//
// La ligne suivant ne compile pas oki
get_truc() << "Bllla bllaaa" << 5 << " truc";
//
// Par contre la ligne suivant compile
get_truc().print("Bllla bllaaa").print(5).print("truc");
Pourquoi la seconde ligne compile ?
Pour moi, les principaux apports sont :
Pour moi, les principaux apports sont :
Pour moi, les principaux apports sont :