OVH Cloud OVH Cloud

peut-on définir une fonction membre statique dans un fichier .cpp ?

35 réponses
Avatar
Aurélien Barbier-Accary
Bonjour,

petite question comme ça, tout est dans le titre.
Puisqu'on peut écrire

// dans le .hpp
classe cA
{
public:
static const double val;
static const double fonc(const double& d) { return 2*d; }
//...
};
// dans le .cpp
const double cA::val = 1.0;

Comment écrire ceci :

// dans le .hpp
classe cB
{
public:
static const double val;
static const double fonc(const double& d);
//...
};
// dans le .cpp
const double cB::val = 1.0;
const double cB::fonc(const double& d) { return 2*d; }

Chez moi (gcc), ça m'indique des erreurs dans la fonction qui suit le prototype
de la fonction membre statique.
J'ai essayé de ne pas définir une fonction mais un pointeur de fonction mais
j'ai la même erreur.

Quelqu'un a déjà vu/utilisé ce genre de choses ?

Aurélien.

10 réponses

1 2 3 4
Avatar
Fabien LE LEZ
On Sat, 15 Oct 2005 01:51:32 +0200, Aurélien Barbier-Accary
:

// dans le .hpp
classe cB


La faute de frappe ici (le "e" à "class") me fait penser que tu n'as
pas fait un copier-coller direct de ton code, et donc que tu n'as pas
tenté de compiler le code posté.

{
public:
static const double val;


Je conseillerais plutôt l'écriture suivante, qui me semble plus claire
(mais qui est parfaitement équivalente) :

static double const val;

static const double fonc(const double& d);


Idem ici :

static double const fonc (double const& d);

... sauf que je ne comprends pas l'utilité du premier "const" ici.
Comeau non plus, d'ailleurs, puisqu'il affiche un warning.

//...
};
// dans le .cpp
const double cB::val = 1.0;
const double cB::fonc(const double& d) { return 2*d; }



Le code que tu as posté est accepté par Comeau C++ (avec un warning
disant que le "const" de la valeur de retour ne sert à rien[*]).
Donc, si ce code n'est pas accepté par gcc, il y a un problème quelque
part.
Quelle version de gcc utilises-tu, au fait ?


[*] warning: type qualifier on return type is meaningless


Chez moi (gcc), ça m'indique des erreurs dans la fonction qui suit le prototype
de la fonction membre statique.


Ça, ça sent le point-virgule oublié.

Avatar
Fabien LE LEZ
On Sat, 15 Oct 2005 01:51:32 +0200, Aurélien Barbier-Accary
:

static const double fonc(const double& d);


Au fait, je reviens sur ce "const" en trop... tu n'aurais pas essayé
de déclarer une fonction qui soit à la fois "static" et "const", par
hasard ?
Si c'est ça, c'est effectivement impossible : une fonction "static"
n'est pas liée à un objet (i.e. "this" n'y existe pas) ; dire qu'elle
ne modifie pas l'objet n'a donc aucun sens.
(Pour la même raison, une telle fonction ne peut pas non plus être
virtuelle.)

Avatar
Aurélien Barbier-Accary
Merci pour ta réponse à cette heure tardive.
Pour la suite, j'ai répondu au coup par coup.

On Sat, 15 Oct 2005 01:51:32 +0200, Aurélien Barbier-Accary

// dans le .hpp
classe cB


La faute de frappe ici (le "e" à "class") me fait penser que tu n'as
pas fait un copier-coller direct de ton code, et donc que tu n'as pas
tenté de compiler le code posté.


Faux... et vrai :-)
Il s'agit de code en partie récupéré dans un fichier volumineux et que j'ai
voulu clarifier. Là où il y a des erreurs, c'est que je l'ai refait "à la main" :-O

static double const fonc (double const& d);

... sauf que je ne comprends pas l'utilité du premier "const" ici.
Comeau non plus, d'ailleurs, puisqu'il affiche un warning.


Toujours un problème de simplification: pour un double il n'y a pas d'intérêt
mais si fonc renvoie un objet d'une classe Truc alors const peut avoir un
intérêt si Truc a des fonctions qui nécessitent une instance constante.
J'ai refait un exemple complet, voir en bas de ce message.
Rq: gcc (version 3.2.3) ne donne pas de warning même pour un double.

// dans le .cpp
const double cB::val = 1.0;
const double cB::fonc(const double& d) { return 2*d; }



Le code que tu as posté est accepté par Comeau C++ (avec un warning
disant que le "const" de la valeur de retour ne sert à rien[*]).
Donc, si ce code n'est pas accepté par gcc, il y a un problème quelque
part.
Quelle version de gcc utilises-tu, au fait ?


[*] warning: type qualifier on return type is meaningless



j'utilise donc gcc 3.2.3 et pour l'écriture "const double" ou "double const",
question d'habitude :-)

Chez moi (gcc), ça m'indique des erreurs dans la fonction qui suit le prototype
de la fonction membre statique.


Ça, ça sent le point-virgule oublié.



Malheureusement non, il y est pourtant bien dans mon exemple :-(

Bon, mon premier message a été fait à la va-vite, donc pour lever toutes les
ambiguités voila un programme complet qui montre les problèmes et les intérêts
des const :

Euh là on est un peu plus tard et l'exemple de programme est fait (ci-dessous)
mais je n'arrive pas à reproduire sur un exemple simple mon problème qui
n'apparait cependant que lorsque je défini dans un .cpp le corps d'une fonction
statique alors que en inline tout compile et fonctionne bien !??
L'exemple ci-dessous à au moins le mérite de montrer que les const imposés pour
les valeurs de retours ne snt pas inutiles ni des erreurs.
Je comprends de moins en moins pourquoi mon vrai code ne compile pas ...
Je vais repartir de lui et le simplifier (pas facile car il y a bcp de
dépendances), on verra bien...


//------------------------------------------------------------------------------
//Truc.hpp

#ifndef __TRUC__
#define __TRUC__

#include <iostream>

class Truc
{
protected:
double x, y;
public:
Truc(const double& a, const double& b) : x(a), y(b) {}
void affiche(void) const { std::cout << x << ", " << y << std::endl; }
Truc& operator+=(const Truc& t) { x+=t.x; y+=t.y; return *this; }
};

class cA1
{
public:
static const Truc val;
static const Truc fonc() { return Truc(-1.0, 0.0); }
// ces valeurs n'ont pas à être modifiées, elles jouent un rôle de constantes
};

class cA2
{
public:
static Truc val;
static Truc fonc() { return Truc(-1.0, 0.0); }
// on autorise la modification -> non sens (cf main.cpp)
};

class cB
{
public:
static const Truc val;
static const Truc fonc(); // corps dans un .cpp (utile si gros)
};

#endif


//------------------------------------------------------------------------------
//Truc.cpp

#include "truc.hpp"

const Truc cA1::val = Truc(1.0, 0.0);

Truc cA2::val = Truc(1.0, 0.0);

const Truc cB::val = Truc(1.0, 0.0);
const Truc cB::fonc(void) { return Truc(-1.0, 0.0); }
// dans mon vrai exemple c'est quand j'utilise cette écriture que ça plante !?!


//------------------------------------------------------------------------------
//main.cpp

#include "truc.hpp"

int main(int argc, char* argv[])
{
(cA2::val += cA2::fonc()).affiche(); // on peut le faire mais ça n'a pas de
sens -> pas cool
// oui c'est moche comme code mais c'est un exemple (abstrait) court

//(cA1::val += cA1::fonc()).affiche();
// erreur de compilation, c'est ce qu'on voulait !!!

Truc mon_cA = cA1::val;
(mon_cA += cA1::fonc()).affiche(); // comme ça c'est logique -> autorisé

cB::fonc().affiche();

return EXIT_SUCCESS;
}


##------------------------------------------------------------------------------
##Makefile

HDRS = truc.hpp
SRCS = main.cpp truc.cpp
OBJS = $(SRCS:.cpp=.o)
EXE = truc.exe
LIBS LIBSDIR
all:
@make -ks $(EXE)

$(EXE): $(OBJS)
g++ $(OBJS) -o $@ $(LIBSDIR) $(LIBS)

clean:
rm -f $(EXE) $(OBJS) *~

%.o: %.cpp $(HDRS)
g++ -c $< -o $@


Avatar
Aurélien Barbier-Accary
On Sat, 15 Oct 2005 01:51:32 +0200, Aurélien Barbier-Accary

static const double fonc(const double& d);



Au fait, je reviens sur ce "const" en trop... tu n'aurais pas essayé
de déclarer une fonction qui soit à la fois "static" et "const", par
hasard ?
Si c'est ça, c'est effectivement impossible : une fonction "static"
n'est pas liée à un objet (i.e. "this" n'y existe pas) ; dire qu'elle
ne modifie pas l'objet n'a donc aucun sens.
(Pour la même raison, une telle fonction ne peut pas non plus être
virtuelle.)



comme j'ai essayé de le montrer dans ma réponse à ton premier message, il n'y a
pas de const en trop et il ne s'agit donc pas d'une tentative de déclaration de
fonction statique constante (qui s'écrirait avec un const à la fin).

Aurélien.


Avatar
Aurélien Barbier-Accary
oulala, j'aurais mieux fait d'aller me coucher hier soir !
J'explique ce qui se passait: j'utilise une fonction statique dans chacune de
mes classes en mode debug pour effectuer un test de chacune des fonctions
implémentées.
Dans une classe j'utilise notamment 3 fonctions qui déclenchent des exceptions
en cas de problème et je les défini à l'aide de functions-try-block,
c'est-à-dire qu'elles ressemblent à quelque chose de ce type :
/<type retour> ma_fonction(<params>)
try{ /* code try */ }
catch(std::exception& e) { std::cerr << e.what() << std::endl; }/
et que donc les blocs try et catch ne sont pas des sous-parties du corps de la
fonction.

J'avais testé ces fonctions (inline) et elles compilaient et fonctionnaient bien
mais il se trouve que quand elles sont utilisées au sein d'une fonction
statique, à la compilation j'ai des erreurs
/warning: control reaches end of non-void function/

Pour éviter les malentendus, je précise que dans ma fonction statique d'une
classe cA, je défini des objets de type cA sur lesquels j'effectue des
opérations (de cA) suceptibles de déclencher des interruptions.

Finalement, si je n'utilise pas une définition par function-try-block mais une
définition plus classique avec des sous-blocs, ça fonctionne.

Le comportement du compilateur me semble bizarre...
Je vais dormir un peu, j'y verrai sans doute plus clair.
Désolé pour la pollution du forum et merci encore à Fabien.
Et si quelqu'un a une idée du pourquoi de ce comportement de gcc je suis preneur!

Aurélien.

PS: pour ceux qui se demandent pourquoi utiliser des functions-try-block :
http://www.yannis.bres.name/Teaching/UNSA/MInfo/C++/Slides/1-Exceptions/index_v3_document.html
http://www.csci.csusb.edu/dick/c++std/cd2/except.html
google
Avatar
Fabien LE LEZ
On Sat, 15 Oct 2005 05:11:41 +0200, Aurélien Barbier-Accary
:

static const Truc val;
static const Truc fonc() { return Truc(-1.0, 0.0); }
// ces valeurs n'ont pas à être modifiées, elles jouent un rôle de constantes


Gnii ?..

Le "static const Truc val;" est correct, il n'y a rien à dire.

Le const de "static const Truc fonc()" est au contraire inutile : même
si tu ne spécifies pas "const", l'objet retourné est de toutes façons
est une rvalue :

class C
{
public:
static int fonc() { return 5; }
};

int main()
{
C::fonc()= 3; // Erreur ici car C::fonc() est une rvalue.
}



const Truc cB::val = Truc(1.0, 0.0);


Pourquoi une écriture si compliquée ?

const Truc cB::val (1.0, 0.0);

est plus simple, et évite une copie inutile.

const Truc cB::fonc(void) { return Truc(-1.0, 0.0); }


C'est vraisemblablement purement cosmétique, mais le "void" est
déconseillé en C++, d'autant que tu ne l'as pas mis dans le prototype
de la fonction.

// dans mon vrai exemple c'est quand j'utilise cette écriture que ça plante !?!


Ça plante ou tu as des erreurs de compilation ?

Quelles sont ces erreurs, au fait ?
Sans avoir les messages d'erreurs exacts, il est bien difficile de
faire autre chose que parler dans le vide...

Avatar
Fabien LE LEZ
On Sat, 15 Oct 2005 05:59:23 +0200, Aurélien Barbier-Accary
:

/<type retour> ma_fonction(<params>)
try{ /* code try */ }
catch(std::exception& e) { std::cerr << e.what() << std::endl; }/


Je ne sais pas bien pourquoi cette syntaxe a été introduite, mais il
me semble qu'elle est totalement inutile.
Encore une facétie des auteurs de la norme ?

Avatar
Franck Branjonneau
Aurélien Barbier-Accary écrivait:

class cA1
{
public:
static const Truc val;
static const Truc fonc() { return Truc(-1.0, 0.0); }
// ces valeurs n'ont pas à être modifiées, elles jouent un rôle de
constantes
};

class cA2
{
public:
static Truc val;
static Truc fonc() { return Truc(-1.0, 0.0); }
// on autorise la modification -> non sens (cf main.cpp)
};


struct cA3 {
static Truc const val;
static Truc fonc() { return Truc(-1.0, 0.0); }
};

const Truc cB::val = Truc(1.0, 0.0);
const Truc cB::fonc(void) { return Truc(-1.0, 0.0); }
// dans mon vrai exemple c'est quand j'utilise cette écriture que ça
plante !?!


Et si tu nous donnais le message d'erreur ?

//(cA1::val += cA1::fonc()).affiche();
// erreur de compilation, c'est ce qu'on voulait !!!


Mais elle n'est pas liée à la constance de la valeur retournée far
cA1::fonc().

cA3::val += cA3::fonc();

donne la même erreur de compilation.

##Makefile


Est-ce vraiment utile ?
--
Franck Branjonneau

Avatar
Franck Branjonneau
Fabien LE LEZ écrivait:

On Sat, 15 Oct 2005 05:59:23 +0200, Aurélien Barbier-Accary
:

/<type retour> ma_fonction(<params>)
try{ /* code try */ }
catch(std::exception& e) { std::cerr << e.what() << std::endl; }/


Je ne sais pas bien pourquoi cette syntaxe a été introduite, mais il
me semble qu'elle est totalement inutile.


Même dans le cas des constructeurs (dont la liste d'initialisation est
non vide) ?
--
Franck Branjonneau


Avatar
Franck Branjonneau
Aurélien Barbier-Accary écrivait:

Chez moi (gcc), ça m'indique des erreurs dans la fonction qui suit
le prototype de la fonction membre statique.


Ton code me semble correct (modulo s/classe/class/). Puisque l'erreur
apparaît après le prototype et uniquement dans le cpp, je chercherais
si je n'inclus pas dans ce cpp un fichier qui définit une macro fonc.

--
Franck Branjonneau

1 2 3 4