Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

namespace et operator

2 réponses
Avatar
Chanclou
Bonjour,

J'ai un gros soucis avec les namespace et les operator de flux.
A la base il y a des transferts de données du genre qui met ou lit les données dans un buffer et lors déchange de
donner. Toute classe qui utilise ce service doivent hériter d'une classe mère :

dans namespace OMK

class OMK_API Flowable
{
public:
~Flowable() {} ;
/// extraction from an input stream
virtual void extract (std::istream & = std::cin) = 0 ;

/// insertion in an output stream
virtual void insertInStream (std::ostream & = std::cout) const = 0 ;

/// unpack from a synchronisation message
virtual void unpack (IncomingSynchronisationMessage &) = 0 ;

/// pack in a synchronisation message
virtual void pack (OutgoingSynchronisationMessage &) const = 0 ;

} ;

Comme il peut être utile d'encapsuler des structures de données car elles peuvent être fournies par ailleur on a créé
une classe template d'encapsulation :

dans namespace OMK::Type la déclaration
template< typename T >
class SimpleTypeT
: public Flowable
{
...
///\brief Insert datas in an output stream
virtual void insertInStream( std::ostream& out = std::cout ) const ;
///\brief Extract datas from an input stream
virtual void extract( std::istream& in = std::cin ) ;

///\brief Pack datas in the message
virtual void pack ( OutgoingSynchronisationMessage& out ) const ;
///\brief Unpack datas from the message
virtual void unpack( IncomingSynchronisationMessage& in ) ;

...
///\brief This member holds the \b value of \ref SimpleTypeT.
///
/// The value of the type.
T _value ;
} ;

dans namespace :: les implémentations
template< typename T > void OMK::Type::SimpleTypeT< T >::insertInStream( std::ostream& out ) const
{ out << _value << " " << " " ; }
template< typename T > void OMK::Type::SimpleTypeT< T >::extract( std::istream& in )
{ in >> _value ; }
template< typename T > void OMK::Type::SimpleTypeT< T >::pack( OMK::OutgoingSynchronisationMessage& out ) const
{ out << _value ; }
template< typename T > void OMK::Type::SimpleTypeT< T >::unpack( OMK::IncomingSynchronisationMessage& in )
{ in >> _value ; }



Donc en gros cette classe appelle les operateurs << et >> pour effectuer l'opération de lecture/écriture dans les buffers.

par exemple on a :
dans namespace ::
template< typename T1, typename T2 >
std::ostream& operator << ( std::ostream& out, const std::pair< T1, T2 >& value )
{
out << value.first << " " << value.second << " " ;
return out ;
}

qui permet de mettre une paire dans le flux.
par exemple OMK::SimpleTypeT< std::pair< int, int > > fonctionne parfaitement

...sauf que des fois non ! Visual sous Win32 est toujours content mais gcc sous linux est "parfois" incapable de
retrouver l'opérateur nécessaire mais pas toujours.
On supputait un problème de namespace, alors on a mis tous les opérateurs dans l'espace de base :: car auparavant les
opérateurs étaient définis dans différents namespace. Cela n'a hélas rien changé :-(

Les sources complètes du projet pour ceux que cela intéresse sont là www.openmask.org

Si quelqu'un a une idée qu'il n'hésite pas ! Merci !

2 réponses

Avatar
James Kanze
On Jun 11, 3:46 pm, Chanclou wrote:

J'ai un gros soucis avec les namespace et les operator de
flux. A la base il y a des transferts de données du genre qui
met ou lit les données dans un buffer et lors déchange de
donner. Toute classe qui utilise ce service doivent hériter
d'une classe mère :

dans namespace OMK

class OMK_API Flowable
{
public:
~Flowable() {} ;
/// extraction from an input stream
virtual void extract (std::istream & = std::cin) = 0 ;

/// insertion in an output stream
virtual void insertInStream (std::ostream & = std::cout) const = 0 ;

/// unpack from a synchronisation message
virtual void unpack (IncomingSynchronisationMessage &) = 0 ;

/// pack in a synchronisation message
virtual void pack (OutgoingSynchronisationMessage &) const = 0 ;
} ;

Comme il peut être utile d'encapsuler des structures de
données car elles peuvent être fournies par ailleur on a créé
une classe template d'encapsulation :

dans namespace OMK::Type la déclaration
template< typename T >
class SimpleTypeT
: public Flowable
{
...
///brief Insert datas in an output stream
virtual void insertInStream( std::ostream& out = std::cout ) const ;
///brief Extract datas from an input stream
virtual void extract( std::istream& in = std::cin ) ;

///brief Pack datas in the message
virtual void pack ( OutgoingSynchronisationMessage& out ) const ;
///brief Unpack datas from the message
virtual void unpack( IncomingSynchronisationMessage& in ) ;

...
///brief This member holds the b value of ref SimpleTypeT.
///
/// The value of the type.
T _value ;
} ;

dans namespace :: les implémentations
template< typename T > void OMK::Type::SimpleTypeT< T >::insertInStream( s td::ostream& out ) const
{ out << _value << " " << " " ; }
template< typename T > void OMK::Type::SimpleTypeT< T >::extract( std::ist ream& in )
{ in >> _value ; }
template< typename T > void OMK::Type::SimpleTypeT< T >::pack( OMK::Outgoi ngSynchronisationMessage& out ) const
{ out << _value ; }
template< typename T > void OMK::Type::SimpleTypeT< T >::unpack( OMK::Inco mingSynchronisationMessage& in )
{ in >> _value ; }


Note bien que même définies dans l'espace référentiel global,
ces fonctions se trouvent dans l'espace référentiel OMK::Type
(et la recherche des noms, dans leurs définitions, se fait à
partir de OMK::Type::SimpleTypeT).

Donc en gros cette classe appelle les operateurs << et >> pour
effectuer l'opération de lecture/écriture dans les buffers.

par exemple on a :
dans namespace ::
template< typename T1, typename T2 >
std::ostream& operator << ( std::ostream& out, const std::pair< T1, T2 >& value )
{
out << value.first << " " << value.second << " " ;
return out ;
}


Ce qui ne marche pas comme on s'y attendrait. Si on invoque
l'opérateur dans un template, et qu'il est « dépendant » (c-à-d
ici qu'un des types T1 ou T2 dépend des paramètres du template,
d'une façon ou d'une autre), la recherche du nom pour
l'opérateur n'inclura pas l'espace global, mais seulement les
espaces impliqués par les paramètres de l'opérateur (std, et les
espaces impliqués par T1 ou T2).

En général, il n'est pas possible de définir des opérateurs <<
et >> pour les types standard qui n'en ont pas. (En général,
ça serait une mauvaise idée de le faire même si l'on pouvait.)
Rien n'empeche, en revanche à ce que tu définisse un
FlowablePair dans ton propre espace référenciel, peut-être même
en dérivant de std::pair.

qui permet de mettre une paire dans le flux.
par exemple OMK::SimpleTypeT< std::pair< int, int > >
fonctionne parfaitement


Ça dépend ce que tu entends par « parfaitement ». En dehors des
templates, pas de problem. Dans un template, si tu fait:
dest << obj ;
où obj a le type d'instantiation du template, c'est clair que
l'expression dépend des paramètres du template, et donc qu'il ne
doit pas y avoir de recherche de l'opérateur dans l'espace
global. (Certains compilateurs le font quand même, soit parce
qu'ils ne sont pas encore à jour avec la norme, soit exprès pour
éviter de casser de l'ancien code inutilement.)

...sauf que des fois non ! Visual sous Win32 est toujours
content mais gcc sous linux est "parfois" incapable de
retrouver l'opérateur nécessaire mais pas toujours. On
supputait un problème de namespace, alors on a mis tous les
opérateurs dans l'espace de base :: car auparavant les
opérateurs étaient définis dans différents namespace. Cela n'a
hélas rien changé :-(

Les sources complètes du projet pour ceux que cela intéresse
sont làwww.openmask.org

Si quelqu'un a une idée qu'il n'hésite pas ! Merci !


Je connais bien le problème, parce que dans les petits
programmes d'essais, j'ai parfois essayé à faire pareil. Dans
des petits programmes d'essai, la solution, c'est de mettre
l'opérateur << dans l'espace std : c'est interdit par la norme,
et ce n'est pas du tout robuste, mais ça permet de faire un
petit essai. Et dans le code de production, évidemment, définir
un tel opérateur poserait tant de problèmes de maintenance qu'il
ne faut de tout façon jamais le faire. (Que doit se passe-t-il
si toi, dans ton module, tu le définis, et qu'un collègue en
fait autant dans son module ?)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Chanclou
Merci pour la réponse éclairante, même si elle signifie qu'il faut que je reprenne tout mon code :(