OVH Cloud OVH Cloud

Sort STL

27 réponses
Avatar
horneta2005
j essaye de mettre en ouvre une fonction de comparaison pour
std::sort mais d apres les exemple que j ai vu je ne comprend pas
leur fonctionnement notament le role de opeator()

10 réponses

1 2 3
Avatar
Stan
a écrit dans le message de news:

j essaye de mettre en ouvre une fonction de comparaison pour
std::sort mais d apres les exemple que j ai vu je ne comprend pas
leur fonctionnement notament le role de opeator()



L'opérateur ( ) permet à un objet d'être utilisé comme une fonction :

par ex, dans :
for_each( l.begin( ), l.end( ) , f );

c'est f ( ) qui sera appelé.

Cela permet d'avoir un moyen générique d'effectuer un traitement.


--
-Stan

Avatar
meow
Si j'ai bien tout compris, l'opérateur () c'est une astuce qui permet
de 'transformer' les fonctions en objets... En C tu passerais un
pointeur de fonction, en C++ tu passes un 'objet fonction', c.à.d un
objet pour lequel l'opérateur () a été redéfini.
L'intérret ? Bein... J'imagine que c'est de pouvoir profiter du typage
et des autres avantages liés à l'objet et que je n'ai pas encore bien
compris ;)... En tout état de cause, ça permet de considérer
réellement les algorithmes eux meme comme des objets.
Avatar
Stan
"meow" a écrit dans le message de news:

Si j'ai bien tout compris, l'opérateur () c'est une astuce qui permet
de 'transformer' les fonctions en objets... En C tu passerais un


Plutôt l'inverse : utiliser des objet comme des fonctions.

L'intérret ? Bein... J'imagine que c'est de pouvoir profiter du typage
et des autres avantages liés à l'objet et que je n'ai pas encore bien



Il y a plusieurs avantages, l'un d'eux est de pourvoir
travailler sur des résultats intermédiaires qui sont stockés dans l'objet.
Un autre est d'avoir une fonction paramètrable ( lors de la construction de
l'objet ).
Il doit y en avoir d'autres encore...

--
-Stan

Avatar
kanze
Stan wrote:
"meow" a écrit dans le message de news:

Si j'ai bien tout compris, l'opérateur () c'est une astuce
qui permet de 'transformer' les fonctions en objets... En C
tu passerais un


Plutôt l'inverse : utiliser des objet comme des fonctions.

L'intérret ? Bein... J'imagine que c'est de pouvoir profiter
du typage et des autres avantages liés à l'objet et que je
n'ai pas encore bien


Il y a plusieurs avantages, l'un d'eux est de pourvoir
travailler sur des résultats intermédiaires qui sont stockés
dans l'objet. Un autre est d'avoir une fonction paramètrable (
lors de la construction de l'objet ).


Je ne comprends pas trop ce deuxième. On peut très bien utilise
un pointeur à fonction, genre :

bool isLessThan( MyType const& lhs, MyType const& rhs ) ;

std::vector< MyType > v ;
std::sort( v.begin(), v.end(), isLessThan ) ;

Il doit y en avoir d'autres encore...


Curieusement : la vitesse. Une fonction comme std::sort ou une
classe comme std::set s'instancie sur un type, non une valeur.
Ici, le type est bool (*)( MyType const&, MyType const& ). Ce
qui ne dit rien au compilateur sur la fonction même ; du coup,
le compilateur doit générer un appel indirect à chaque
comparaison. (En principe, l'optimisateur pourrait l'éliminer,
mais dans la pratique...) Tandis qu'avec l'objet, la fonction
appelée dépend uniquement du type d'instantiation, et non de sa
valeur. Du coup, le compilateur peut générer l'appel statique,
voire même générer la fonction inline le cas échéant.

Aussi, dans le cas des collections comme std::set, tu n'as pas
besoin de fournir une valeur. Si tu veux utliser une fonction,
il faudrait déclarer l'ensemble comme :

std::set< MyType, bool (*)( MyType const&, MyType const& ) >
aSet( isLessThan ) ;

--
James Kanze GABI Software
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
Stan
"kanze" a écrit dans le message de news:


Il y a plusieurs avantages, l'un d'eux est de pourvoir
travailler sur des résultats intermédiaires qui sont stockés
dans l'objet. Un autre est d'avoir une fonction paramètrable (
lors de la construction de l'objet ).


Je ne comprends pas trop ce deuxième. On peut très bien utilise
un pointeur à fonction, genre :

bool isLessThan( MyType const& lhs, MyType const& rhs ) ;

std::vector< MyType > v ;
std::sort( v.begin(), v.end(), isLessThan ) ;


Comment fait-on avec une fonction pour avoir
l'équivalent de : std::sort( v.begin(), v.end(), isLessThan( myValue ) ) ?


--
-Stan


Avatar
kanze
Stan wrote:
"kanze" a écrit dans le message de news:


Il y a plusieurs avantages, l'un d'eux est de pourvoir
travailler sur des résultats intermédiaires qui sont
stockés dans l'objet. Un autre est d'avoir une fonction
paramètrable ( lors de la construction de l'objet ).


Je ne comprends pas trop ce deuxième. On peut très bien
utilise un pointeur à fonction, genre :

bool isLessThan( MyType const& lhs, MyType const& rhs ) ;

std::vector< MyType > v ;
std::sort( v.begin(), v.end(), isLessThan ) ;


Comment fait-on avec une fonction pour avoir l'équivalent de :
std::sort( v.begin(), v.end(), isLessThan( myValue ) ) ?


On ne fait pas.

Enfin, on pourrait écrire une fonction de comparaison qui
utilisait une variable globale, et y mettre myValue. Mais dans
ce cas-là, c'est beaucoup plus propre d'utiliser un objet
fonctionnel.

Attention quand même avec les objets fonctionnels. Ils vont être
copiés à droit et à gauche. Ce qui veut dire que si tu veux
qu'ils utilisent un état évolutif, il faut s'arranger pour que
toutes les instances en partagent cet état.

--
James Kanze GABI Software
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
Fabien LE LEZ
On 5 Oct 2005 00:42:26 -0700, "kanze" :

Attention quand même avec les objets fonctionnels. Ils vont être
copiés à droit et à gauche.


Donc, pas de fonctions virtuelles...

Ce qui veut dire que si tu veux
qu'ils utilisent un état évolutif,


N'est-ce pas a priori une mauvaise idée de toutes façons, puisqu'on
n'est jamais trop sûr à l'avance de l'ordre dans lequel les éléments
seront traités ?

Avatar
Stan
"Fabien LE LEZ" a écrit dans le message de
news:
| On 5 Oct 2005 00:42:26 -0700, "kanze" :
|
| >Attention quand même avec les objets fonctionnels. Ils vont être
| >copiés à droit et à gauche.
|
| Donc, pas de fonctions virtuelles...
|
| >Ce qui veut dire que si tu veux
| >qu'ils utilisent un état évolutif,
|
| N'est-ce pas a priori une mauvaise idée de toutes façons, puisqu'on
| n'est jamais trop sûr à l'avance de l'ordre dans lequel les éléments
| seront traités ?


Si l'ordre a de l'importance, il suffit ( si c'est possible ) de trier
avec le prédicat qui convient.

Si l'opération est commutative, le pb ne se pose pas, l'exemple
typique est la sommation :

TSum sum(0);

for_each( v.begin( ), v.end( ), sum );
std::cout << "total: " << sum.res( ) << std::endl;

Ce serait dommage de s'en priver.

--
-Stan
Avatar
kanze
Fabien LE LEZ wrote:
On 5 Oct 2005 00:42:26 -0700, "kanze" :

Attention quand même avec les objets fonctionnels. Ils vont
être copiés à droit et à gauche.


Donc, pas de fonctions virtuelles...

Ce qui veut dire que si tu veux qu'ils utilisent un état
évolutif,


N'est-ce pas a priori une mauvaise idée de toutes façons,
puisqu'on n'est jamais trop sûr à l'avance de l'ordre dans
lequel les éléments seront traités ?


Si la fonction accepte un forward iterator (voire même un input
iterator), et tu lui files un forward iterator, tu sais bien
dans quel ordre les éléments seront traités. Dans certaines
fonctions, aussi, il est dit qu'elle renvoie un itérateur au
*premier* élément, avec parfois des exigeances de complexité qui
ne permettent que de visiter les éléments dans l'ordre. Et
enfin, for_each garantit explicitement l'ordre.

--
James Kanze GABI Software
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
kanze
Fabien LE LEZ wrote:
On 5 Oct 2005 00:42:26 -0700, "kanze" :

Attention quand même avec les objets fonctionnels. Ils vont
être copiés à droit et à gauche.


Donc, pas de fonctions virtuelles...

Ce qui veut dire que si tu veux
qu'ils utilisent un état évolutif,


N'est-ce pas a priori une mauvaise idée de toutes façons,
puisqu'on n'est jamais trop sûr à l'avance de l'ordre dans
lequel les éléments seront traités ?


Il me vient à l'ésprit que c'est pas bête ce que tu dis. Imagine
que tu veux trouver le premier élément dans un tableau d'entiers
qui s'écarte de plus de N du moyen vu jusqu'à là. On aurait
donc:

class CondImpl
{
public:
explicit CondImpl( int limit )
: myLimit( limit )
, myCount( 0 )
, myTotal( 0 )
{
}

bool operator()( int elem )
{
myTotal += elem ;
++ myCount ;
return abs( myTotal / myCount - elem ) > myLimit ;
}

private:
int myLimit ;
size_t myCount ;
int myTotal ;
} ;

class Cond
{
public:
explicit Cond( CondImpl* impl )
: myImpl( imple )
{
}
bool operator()( int elem ) const
{
return (*myImpl)( elem ) ;
}
private:
CondImpl* myImpl ;
}



bool
dataOK( std::vector< int > const& v )
{
static int const limit = 5 ;
CondImpl c ;
return std::find_if( v.begin(), v.end(), Cond( &c ) ) ==
v.end() ;
}

Est-ce qu'il serait légal ? Est-ce qu'il doit l'être ?

Suppose que je remplace les v.begin() par un itérateur wrapper
qui n'est que forward iterator. Est-ce que ça influe sur la
légalité ?

--
James Kanze GABI Software
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


1 2 3