OVH Cloud OVH Cloud

initialisation et double déclaration de données static d'un objet non instancié

119 réponses
Avatar
heinquoi
Bjr,
j'ai un pb de compréhension sur ce code:

class Main
{
public:
static HINSTANCE hInstance;
static HINSTANCE hPrevInstance;
static int nCmdShow;
static int MessageLoop( void );
};

HINSTANCE Main::hInstance = 0; // ici, je devrais avoir une
erreur
HINSTANCE Main::hPrevInstance = 0; // ici, aussi

il y a une double déclaration non ?
Si quelqu'un peut m'éclairer ? Et l'objet n'est meme pas initialisé.
Cordialement
Heinquoi

10 réponses

8 9 10 11 12
Avatar
Gabriel Dos Reis
James Kanze writes:

| Gabriel Dos Reis writes:
|
| [...]
| |> | Je dirais une classe locale à une fonction, et je peux
| |> | entrevoir les raisons poussant à interdir les variables membres
| |> | statiques dans de telles classes [*], mais j'aimerais être
| |> | sûr.
|
| |> | [*] Par exemple le fait qu'une fonction peut être appelée
| |> | plusieurs fois simultanément (récursion), auquel cas, faut-il
| |> | avoir une instance du membre statique pour l'entiéreté de ces
| |> | classes, ou une par appel de fonction (ce qui ne colle plus
| |> | avec « une instance dans tout le programme ») ?
|
| |> Une définition d'une classe locale n'est pas « instanciée » à chaque
| |> appel de la fonction -- ce qui soulèverait la même question dont tu
| |> parles -- donc, je ne pense pas que cette question se pose ou que ce
| |> soit la raison pour laquelle c'est interdit. Une membre statique
| |> « appartient » à sa classe, donc devrait subir un sort similaire à sa
| |> classe.
|
| Je croyais plus simplement : il faut définir une variable statique en
| dehors de la classe. Or, dans une classe locale, il faut définir tout
| dans la classe ; il n'y a pas de syntaxe qui permet une définition en
| dehors de la classe.

C'est une raison possible, mais vu que les auteurs de compilateurs se
sont mis à modifier la norme pour « optimiser » la notion de donnée
membre statique, une donnée membre statique const intégrale n'a pas
forcément besoin d'étre définie ailleurs.

-- Gaby
Avatar
drkm
Gabriel Dos Reis writes:

Désolé pour cette réponse un peut tardive. Je viens de relire ton
article et un point ne m'est plus apparu clair. Il s'agissait d'une
discussion sur l'intervention de static dans le Koenig Lookup.

[explications très intéressantes de l'« Argument dependent name lookup »]

// foo.C
#include "sum.h"
namespace N {
struct foo {
// ...
};

foo add(foo, foo) { ... } // #1
}

int main()
{
N::foo foos[930];
N::foo s = sum(foos, 903); // #2
}

Dans #2, l'instantiation de sum<> va trouver le add() en ligne #1.

Cependant, si comme certains semblent l'adopter en règle, le add dans
N:: a été déclaré static parce qu'elle ne sert que dans foo.C,


Heu, quand tu dis « comme certains semblent l'adopter en règle », tu
veux dire que cela ne devrait pas être ?

même si
elle est trouvée par ADL, la seconde phase de résolution des noms va
l'ignorer, parce qu'elle a un linkage interne. Ce qui provoquera une
erreur -- même si la add() se trouve dans la même unité de traduction
que son utilisation.


C'est donc bien le comportement prescrit par la norme ? Il faut
l'écarter, même si elle est trouvée dans la même TU (je demande
confirmation, car cela m'étonne) ? Peux-tu me donner une référence
de verset, stp ?

--drkm

Avatar
Gabriel Dos Reis
drkm writes:

| Gabriel Dos Reis writes:
|
| Désolé pour cette réponse un peut tardive. Je viens de relire ton
| article et un point ne m'est plus apparu clair. Il s'agissait d'une
| discussion sur l'intervention de static dans le Koenig Lookup.
|
| > [explications très intéressantes de l'« Argument dependent name lookup »]
|
| > // foo.C
| > #include "sum.h"
| > namespace N {
| > struct foo {
| > // ...
| > };
|
| > foo add(foo, foo) { ... } // #1
| > }
|
| > int main()
| > {
| > N::foo foos[930];
| > N::foo s = sum(foos, 903); // #2
| > }
|
| > Dans #2, l'instantiation de sum<> va trouver le add() en ligne #1.
|
| > Cependant, si comme certains semblent l'adopter en règle, le add dans
| > N:: a été déclaré static parce qu'elle ne sert que dans foo.C,
|
| Heu, quand tu dis « comme certains semblent l'adopter en règle », tu
| veux dire que cela ne devrait pas être ?

L'utilisation de « static » pour changer le linkage n'aurait jamais dû
survenir.

| > même si
| > elle est trouvée par ADL, la seconde phase de résolution des noms va
| > l'ignorer, parce qu'elle a un linkage interne. Ce qui provoquera une
| > erreur -- même si la add() se trouve dans la même unité de traduction
| > que son utilisation.
|
| C'est donc bien le comportement prescrit par la norme ?

Oui, monsieur.

| Il faut
| l'écarter, même si elle est trouvée dans la même TU (je demande
| confirmation, car cela m'étonne) ?

Oui, monsieur.

| Peux-tu me donner une référence de verset, stp ?

Oui, monsieur.

14.6.4.2/1

For a function call that depends on a template parameter, if the
function name is an unqualified-id but not a template-id, the
candidate functions are found using the usual lookup rules (3.4.1,
3.4.2) except that:

-- For the part of the lookup using unqualified name lookup (3.4.1),
only function declarations with external linkage from the
template definition context are found.

-- For the part of the lookup using associated namespaces (3.4.2),
only function declarations with external linkage found in either
the template definition context or the template instantiation
context are found.

If the call would be ill-formed or would find a better match had the
lookup within the associated namespaces considered all the function
declarations with external linkage introduced in those namespaces in all
translation units, not just considering those declarations found in
the template definition and template instantiation contexts, then
the program has undefined behavior.


-- Gaby
Avatar
Gabriel Dos Reis
writes:

[ Le contexte était l'impact de « static » pour les fonctions
non-membres sur la recherche de noms dans les templates, définitions
ou instantiations. ]

| Gabriel Dos Reis wrote in message
| news:...
|
| > 14.6.4.2/1
|
| > For a function call that depends on a template parameter, if the
| > function name is an unqualified-id but not a template-id, the
| > candidate functions are found using the usual lookup rules (3.4.1,
| > 3.4.2) except that:
|
| > -- For the part of the lookup using unqualified name lookup (3.4.1),
| > only function declarations with external linkage from the
| > template definition context are found.
|
| > -- For the part of the lookup using associated namespaces (3.4.2),
| > only function declarations with external linkage found in either
| > the template definition context or the template instantiation
| > context are found.
|
| > If the call would be ill-formed or would find a better match had the
| > lookup within the associated namespaces considered all the function
| > declarations with external linkage introduced in those namespaces in all
| > translation units, not just considering those declarations found in
| > the template definition and template instantiation contexts, then
| > the program has undefined behavior.
|
| Je ne sais pas si j'ai bien compris. Considérons le programme suivant :
|
| #include <ostream>
| #include <iostream>
|
| template< typename T >
| void
| dump( char const* name, T const& value )
| {
| std::cout << name << " = " << value << 'n' ;
| }
|
| struct C
| {
| int val ;
| C( int init ) : val( init ) {}
| } ;
|
| std::ostream&
| operator<<( std::ostream& out, C value )
| {
| out << value.val ;
| return out ;
| }
|
| int
| main()
| {
| C c( 42 ) ;
| dump( "c", c ) ;
| return 0 ;
| }
|
| Qu'est-ce que ce passage signifie à son égard ?

Il n'est pas applicable parce que aucune de tes fonctions avec un nom
dépendant n'a un linkage interne.

| Qu'il est illégal (parce que la recherche non-qualifiée se fait
| uniquement dans le contexte de la définition du template, et ne
| trouve pas l'opérateur << qui convient) ?

Non, il est bien valide parce que les trois operator<< n'ont pas de
linkage internes et la recherche de noms (les deux formes) les
trouvera.

| Qu'il a un comportement indéfini (à cause du dernier paragraphe) ? Ou
| est-ce que je n'ai rien compris, comme d'habitude ? (Le code marche
| comme je m'y attendrais de façon naïve avec g++ 3.3.1.

Je crois que tu n'as pas tenu cmpte du contexte de la discussion :

Pendant que certaines personnes s'acharnaient à
donner à static, son seul sens qu'il aurait dû avoir, d'autres
personnes ont trouvé l'opportunité de faire en sorte qu'il n'affecte
plus seulement le linkage mais aussi name lookup


| Mais le fait que
| le code marche ne prouve pas l'absense du comportement indéfini. Et je
| ne crois pas que g++ 3.3.1 soit 100% conforme non plus en ce qui
| concerne la recherche des noms dans les templates.)

mais dans ce cas précis, il fait la bonne chose :-)

-- Gaby

Avatar
kanze
Gabriel Dos Reis wrote in message
news:...

14.6.4.2/1

For a function call that depends on a template parameter, if the
function name is an unqualified-id but not a template-id, the
candidate functions are found using the usual lookup rules (3.4.1,
3.4.2) except that:

-- For the part of the lookup using unqualified name lookup (3.4.1),
only function declarations with external linkage from the
template definition context are found.

-- For the part of the lookup using associated namespaces (3.4.2),
only function declarations with external linkage found in either
the template definition context or the template instantiation
context are found.

If the call would be ill-formed or would find a better match had the
lookup within the associated namespaces considered all the function
declarations with external linkage introduced in those namespaces in all
translation units, not just considering those declarations found in
the template definition and template instantiation contexts, then
the program has undefined behavior.


Je ne sais pas si j'ai bien compris. Considérons le programme suivant :

#include <ostream>
#include <iostream>

template< typename T >
void
dump( char const* name, T const& value )
{
std::cout << name << " = " << value << 'n' ;
}

struct C
{
int val ;
C( int init ) : val( init ) {}
} ;

std::ostream&
operator<<( std::ostream& out, C value )
{
out << value.val ;
return out ;
}

int
main()
{
C c( 42 ) ;
dump( "c", c ) ;
return 0 ;
}

Qu'est-ce que ce passage signifie à son égard ? Qu'il est illégal (parce
que la recherche non-qualifiée se fait uniquement dans le contexte de la
définition du template, et ne trouve pas l'opérateur << qui convient) ?
Qu'il a un comportement indéfini (à cause du dernier paragraphe) ? Ou
est-ce que je n'ai rien compris, comme d'habitude ? (Le code marche
comme je m'y attendrais de façon naïve avec g++ 3.3.1. Mais le fait que
le code marche ne prouve pas l'absense du comportement indéfini. Et je
ne crois pas que g++ 3.3.1 soit 100% conforme non plus en ce qui
concerne la recherche des noms dans les templates.)

--
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
Jean-Marc Bourguet
writes:

Gabriel Dos Reis wrote in message
news:...

14.6.4.2/1

For a function call that depends on a template parameter, if the
function name is an unqualified-id but not a template-id, the
candidate functions are found using the usual lookup rules (3.4.1,
3.4.2) except that:

-- For the part of the lookup using unqualified name lookup (3.4.1),
only function declarations with external linkage from the
template definition context are found.

-- For the part of the lookup using associated namespaces (3.4.2),
only function declarations with external linkage found in either
the template definition context or the template instantiation
context are found.

If the call would be ill-formed or would find a better match had the
lookup within the associated namespaces considered all the function
declarations with external linkage introduced in those namespaces in all
translation units, not just considering those declarations found in
the template definition and template instantiation contexts, then
the program has undefined behavior.


Je ne sais pas si j'ai bien compris. Considérons le programme suivant :

#include <ostream>
#include <iostream>

template< typename T >
void
dump( char const* name, T const& value )
{
std::cout << name << " = " << value << 'n' ;
}

struct C
{
int val ;
C( int init ) : val( init ) {}
} ;

std::ostream&
operator<<( std::ostream& out, C value )
{
out << value.val ;
return out ;
}

int
main()
{
C c( 42 ) ;
dump( "c", c ) ;
return 0 ;
}

Qu'est-ce que ce passage signifie à son égard ?


A mon avis, on trouve l'operator<< (qui a un linkage externe) par le
recherche utilisant les namespace associes dans le contexte de
l'instanciation (le dump dans main). Comme il n'y a qu'une unite de
traduction et que le contexte d'instanciation comporte toutes les
declarations de linkage externe de celle-ci, le dernier paragraphe
n'est pas a considerer.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org


Avatar
kanze
Gabriel Dos Reis wrote in message
news:...

writes:

[ Le contexte était l'impact de « static » pour les fonctions
non-membres sur la recherche de noms dans les templates, définitions
ou instantiations. ]


Je connais le contexte de la discussion jusqu'ici, mais il y avait des
choses dans le texte que tu as cité que je ne comprends pas très bien.
Independamment du contexte de la discussion jusqu'ici.

| Gabriel Dos Reis wrote in message
| news:...

| > 14.6.4.2/1

| > For a function call that depends on a template parameter, if the
| > function name is an unqualified-id but not a template-id, the
| > candidate functions are found using the usual lookup rules (3.4.1,
| > 3.4.2) except that:

| > -- For the part of the lookup using unqualified name lookup (3.4.1),
| > only function declarations with external linkage from the
| > template definition context are found.

| > -- For the part of the lookup using associated namespaces (3.4.2),
| > only function declarations with external linkage found in either
| > the template definition context or the template instantiation
| > context are found.

| > If the call would be ill-formed or would find a better match had
| > the lookup within the associated namespaces considered all the
| > function declarations with external linkage introduced in those
| > namespaces in all translation units, not just considering those
| > declarations found in the template definition and template
| > instantiation contexts, then the program has undefined behavior.

| Je ne sais pas si j'ai bien compris. Considérons le programme suivant :


Je crois que je n'ai toujours pas compris.

| #include <ostream>
| #include <iostream>

| template< typename T >
| void
| dump( char const* name, T const& value )
| {
| std::cout << name << " = " << value << 'n' ;
| }

| struct C
| {
| int val ;
| C( int init ) : val( init ) {}
| } ;

| std::ostream&
| operator<<( std::ostream& out, C value )
| {
| out << value.val ;
| return out ;
| }

| int
| main()
| {
| C c( 42 ) ;
| dump( "c", c ) ;
| return 0 ;
| }

| Qu'est-ce que ce passage signifie à son égard ?

Il n'est pas applicable parce que aucune de tes fonctions avec un nom
dépendant n'a un linkage interne.


Le passage cité dit bien « external linkage », et c'est bien l'aspect
pertinent à la discussion en cours. Mais au moins qu'il y a quelque
chose que j'ai raté, le passage parle en général de la recherche du nom
dans une instantiation de template. Le passage est donc relevent à la
recherche de l'opérateur << dans dump, non ?

| Qu'il est illégal (parce que la recherche non-qualifiée se fait
| uniquement dans le contexte de la définition du template, et ne
| trouve pas l'opérateur << qui convient) ?

Non, il est bien valide parce que les trois operator<< n'ont pas de
linkage internes et la recherche de noms (les deux formes) les
trouvera.


La recherche de noms dans le contexte de la définition du template ne
doit pas le retrouver, ou ? Ou sinon, il y a quelque chose que je n'ai
vraiment pas compris.

Il y a ici deux recherches de noms (selon le passage que tu cites) :
celle « using unqualified lookup (3.4.1) », et celle « using associated
namespaces (3.4.2) » (ce qu'on appelle parfois « Koenig lookup », je
crois, ou est-ce que je le confonds avec quelque chose d'autre). Or,
dans la mésure que ma classe C n'est pas dans un namespace, SI J'AI BIEN
COMPRIS (parce que j'avoue qu'ici, je ne m'y connais pas très bien), la
recherche conditionnée sur les namespaces ne s'applique pas, au moins
pas en ce qui concerne la classe C. C-à-d (encore, si j'ai bien compris)
que la recherche citée dans le deuxième point ne s'y applique pas. Et la
recherche du premier point ne s'effectue que dans le contexte de la
définition du template, c-à-d avant la déclaration/définition de
l'opérateur << pour C.

| Qu'il a un comportement indéfini (à cause du dernier paragraphe) ?
| Ou est-ce que je n'ai rien compris, comme d'habitude ? (Le code
| marche comme je m'y attendrais de façon naïve avec g++ 3.3.1.

Je crois que tu n'as pas tenu cmpte du contexte de la discussion :


Je n'ai pas tenu compte du contexte de la discussion. Je me pose une
question sur le passage que tu as cité, que j'ai du mal à comprendre. Ma
question n'a rien à voir avec la discussion précédante. (Peut-être
j'aurais dû changer la ligne de sujet. Je m'excuse, mais je n'y ai pas
pensé.)

Pendant que certaines personnes s'acharnaient à donner à static,
son seul sens qu'il aurait dû avoir, d'autres personnes ont
trouvé l'opportunité de faire en sorte qu'il n'affecte plus
seulement le linkage mais aussi name lookup


| Mais le fait que le code marche ne prouve pas l'absense du
| comportement indéfini. Et je ne crois pas que g++ 3.3.1 soit 100%
| conforme non plus en ce qui concerne la recherche des noms dans les
| templates.)

mais dans ce cas précis, il fait la bonne chose :-)


Peut-être. Si (comme je soupçonne) c'est un comportement indéfini,
n'importe ce qu'il fait est la bonne chose:-). Ce qui ne prouve toujours
pas que mon code est correct.

Mais ma question reste : si j'ai bien compris le passage que tu as cité,
le compilateur ne peut pas trouver l'opérateur pour C selon le premier
point, parce que la recherche des noms là ne se fait que dans le
contexte de la définition du template, et dans le contexte de sa
définition, l'opérateur << voulu n'est pas encore visible, parce qu'il
n'a pas encore été déclaré. Et il ne peut pas trouver l'opérateur selon
le seconde point, parce que la recherche dépendante du paramètre ne
retrouve jamais des noms dans le namespace global.

Mais est-ce vrai, ça ? Je me rappelle des histoires, mais l'objet dans
le namespace global était toujours un type de base, comme double.
Peut-être mon erreur, c'est simplement que j'ai exterpolé quelque chose
qui ne s'applique qu'aux types de base à tous les types dans le
namespace global. (Dans §3.4.2/2, il dit « If T is a class type, [...].
Its associated namespaces are the namespaces in which its associated
classes are defined. » Est-ce que le namespace global compte ici ? Dans
la mésure que ce n'est pas un « namespace » proprement dit)

--
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
Jean-Marc Bourguet wrote in message
news:...
writes:

Gabriel Dos Reis wrote in message
news:...

14.6.4.2/1

For a function call that depends on a template parameter, if the
function name is an unqualified-id but not a template-id, the
candidate functions are found using the usual lookup rules
(3.4.1, 3.4.2) except that:

-- For the part of the lookup using unqualified name lookup (3.4.1),
only function declarations with external linkage from the
template definition context are found.

-- For the part of the lookup using associated namespaces (3.4.2),
only function declarations with external linkage found in either
the template definition context or the template instantiation
context are found.

If the call would be ill-formed or would find a better match had
the lookup within the associated namespaces considered all the
function declarations with external linkage introduced in those
namespaces in all translation units, not just considering those
declarations found in the template definition and template
instantiation contexts, then the program has undefined behavior.


Je ne sais pas si j'ai bien compris. Considérons le programme
suivant :

#include <ostream>
#include <iostream>

template< typename T >
void
dump( char const* name, T const& value )
{
std::cout << name << " = " << value << 'n' ;
}

struct C
{
int val ;
C( int init ) : val( init ) {}
} ;

std::ostream&
operator<<( std::ostream& out, C value )
{
out << value.val ;
return out ;
}

int
main()
{
C c( 42 ) ;
dump( "c", c ) ;
return 0 ;
}

Qu'est-ce que ce passage signifie à son égard ?


A mon avis, on trouve l'operator<< (qui a un linkage externe) par le
recherche utilisant les namespace associes dans le contexte de
l'instanciation (le dump dans main). Comme il n'y a qu'une unite de
traduction et que le contexte d'instanciation comporte toutes les
declarations de linkage externe de celle-ci, le dernier paragraphe
n'est pas a considerer.


C'est ce que je commence à croire moi-même. C'est que selon ma premier
analyse, C ne se trouvait pas dans un namespace ; c'est donc que la
recherche dépendante aux paramètres ne pourrait pas le retrouver. Mais
tout compte fait, je crois que la norme considère le namespace global
comme n'importe quel autre namespace -- l'absense d'un namespace, c'est
un namespace.

C'est raisonable, mais dans ce cas-là, pourquoi ne pas y mettre les
types de base aussi ?

Mais je deviens de plus en plus confus. Ce qui m'a mis la puce à
l'oreille, c'est que je me suis rappelé d'un cas où on avait surchargé
l'opérateur << pour un std::vector< double >, et que le compilateur n'a
pas trouver ce surcharge quand on utiliser un std::ostream_iterator. (Je
crois que c'était le cas. Je n'ai plus le code exact sous la main.) OK,
je comprends. Le problème, c'est que double, c'est un type de base, qui
n'est dans aucun namespace, même pas le namespace global. Sauf que je
viens d'essayer avec mon exemple ci-dessus, en remplaçant C par
std::vector<double>, et ça compile aussi. Alors, pourquoi ça compile
avec mon template dump, et non avec ostream_iterator ?

Une question subsidiaire serait : est-ce que le tout n'est pas un peu
trop compliqué ? Au point, même, que si on se sert des templates, on ne
peut plus savoir si son code est correct ou non.

--
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
Jean-Marc Bourguet
writes:

Jean-Marc Bourguet wrote in message
news:...
writes:

Gabriel Dos Reis wrote in message
news:...

14.6.4.2/1

For a function call that depends on a template parameter, if the
function name is an unqualified-id but not a template-id, the
candidate functions are found using the usual lookup rules
(3.4.1, 3.4.2) except that:

-- For the part of the lookup using unqualified name lookup (3.4.1),
only function declarations with external linkage from the
template definition context are found.

-- For the part of the lookup using associated namespaces (3.4.2),
only function declarations with external linkage found in either
the template definition context or the template instantiation
context are found.

If the call would be ill-formed or would find a better match had
the lookup within the associated namespaces considered all the
function declarations with external linkage introduced in those
namespaces in all translation units, not just considering those
declarations found in the template definition and template
instantiation contexts, then the program has undefined behavior.


Je ne sais pas si j'ai bien compris. Considérons le programme
suivant :

#include <ostream>
#include <iostream>

template< typename T >
void
dump( char const* name, T const& value )
{
std::cout << name << " = " << value << 'n' ;
}

struct C
{
int val ;
C( int init ) : val( init ) {}
} ;

std::ostream&
operator<<( std::ostream& out, C value )
{
out << value.val ;
return out ;
}

int
main()
{
C c( 42 ) ;
dump( "c", c ) ;
return 0 ;
}

Qu'est-ce que ce passage signifie à son égard ?


A mon avis, on trouve l'operator<< (qui a un linkage externe) par le
recherche utilisant les namespace associes dans le contexte de
l'instanciation (le dump dans main). Comme il n'y a qu'une unite de
traduction et que le contexte d'instanciation comporte toutes les
declarations de linkage externe de celle-ci, le dernier paragraphe
n'est pas a considerer.


C'est ce que je commence à croire moi-même. C'est que selon ma premier
analyse, C ne se trouvait pas dans un namespace ; c'est donc que la
recherche dépendante aux paramètres ne pourrait pas le retrouver. Mais
tout compte fait, je crois que la norme considère le namespace global
comme n'importe quel autre namespace -- l'absense d'un namespace, c'est
un namespace.


C'est ce que je comprends.

C'est raisonable, mais dans ce cas-là, pourquoi ne pas y mettre les
types de base aussi ?


J'ai ete surpris de l'apprendre quand j'essayais de faire une
proposition pour un "typedef" introduisant des nouveaux types plutot
que des synonymes. J'ai donc pas de bonne reponse.

Mais je deviens de plus en plus confus. Ce qui m'a mis la puce à
l'oreille, c'est que je me suis rappelé d'un cas où on avait surchargé
l'opérateur << pour un std::vector< double >, et que le compilateur n'a
pas trouver ce surcharge quand on utiliser un std::ostream_iterator. (Je
crois que c'était le cas. Je n'ai plus le code exact sous la main.) OK,
je comprends. Le problème, c'est que double, c'est un type de base, qui
n'est dans aucun namespace, même pas le namespace global. Sauf que je
viens d'essayer avec mon exemple ci-dessus, en remplaçant C par
std::vector<double>, et ça compile aussi. Alors, pourquoi ça compile
avec mon template dump, et non avec ostream_iterator ?


como refuse

#include <vector>

template <typename T>
int f(T t) {
return g(t);
}

int g(double) {
return 4;
}

int g(std::vector<double>const&) {
return 5;
}

namespace ns {
class Y {
};

int g(Y) {
return 6;
}
}

int foo(double x) {
std::vector<double> v;
ns::Y y;

return f(x)
+ f(v)
+ f(y);
}

avec des erreurs pour f<double> et f<std::vector<double> > et pas pour
f<ns::Y> comme je m'y attendais (double pas de namespace associe,
std::vector a std comme namespace associe). Donc pour moi c'est
bug/not implemented yet dans le compilateur que tu as essaye

Une question subsidiaire serait : est-ce que le tout n'est pas un
peu trop compliqué ? Au point, même, que si on se sert des
templates, on ne peut plus savoir si son code est correct ou non.


Qu'est est l'antecedant de "tout"? Quelles sont les alternatives?
Quel est la situation minimale acceptable? La recherche des noms et
les templates ont des interactions complexes, mais je crains que pour
trouver des alternatives significativement plus simples, il faille
perdre en fonctionnalite/facilite d'utilisation.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org




Avatar
Gabriel Dos Reis
writes:

[...]

| Il y a ici deux recherches de noms (selon le passage que tu cites) :
| celle « using unqualified lookup (3.4.1) », et celle « using associated
| namespaces (3.4.2) » (ce qu'on appelle parfois « Koenig lookup », je

Oui.

| crois, ou est-ce que je le confonds avec quelque chose d'autre). Or,
| dans la mésure que ma classe C n'est pas dans un namespace,

Comment ça ta classe n'est pas dans un namespace ?
3.3.5/3

The outermost declarative region of a translation unit is also a
namespace, called the global namespace. A name declared in the
global namespace has global namespace scope (also called global
scope). The potential scope of such a name begins at its point of
declaration (3.3.1) and ends at the end of the translation unit
that is its declarative region. Names with global namespace scope are
said to be global.


| SI J'AI BIEN
| COMPRIS (parce que j'avoue qu'ici, je ne m'y connais pas très bien), la
| recherche conditionnée sur les namespaces ne s'applique pas, au moins

La portée globale est une portée de namespace (autrement le monde
s'effondrerait) et le deuxième point cité s'applique bien.

[...]

| > | Mais le fait que le code marche ne prouve pas l'absense du
| > | comportement indéfini. Et je ne crois pas que g++ 3.3.1 soit 100%
| > | conforme non plus en ce qui concerne la recherche des noms dans les
| > | templates.)
|
| > mais dans ce cas précis, il fait la bonne chose :-)
|
| Peut-être. Si (comme je soupçonne) c'est un comportement indéfini,

je ne vois pas le l'ombre du début d'un soupçon d'un fonctionnement
indéfini.

| n'importe ce qu'il fait est la bonne chose:-). Ce qui ne prouve toujours
| pas que mon code est correct.
|
| Mais ma question reste : si j'ai bien compris le passage que tu as cité,
| le compilateur ne peut pas trouver l'opérateur pour C selon le premier
| point, parce que la recherche des noms là ne se fait que dans le
| contexte de la définition du template, et dans le contexte de sa
| définition, l'opérateur << voulu n'est pas encore visible, parce qu'il
| n'a pas encore été déclaré. Et il ne peut pas trouver l'opérateur selon
| le seconde point, parce que la recherche dépendante du paramètre ne
| retrouve jamais des noms dans le namespace global.
|
| Mais est-ce vrai, ça ?

Ce n'est pas vrai. La raison est que la portée globale est un
namespace et Koenig lookup s'applique bien.

| Je me rappelle des histoires, mais l'objet dans
| le namespace global était toujours un type de base, comme double.

Ces histoires sont un peu différentes : la raison est que l'ensemble
des namespaces associés à un type fondamental ou composite de types
fondamentaux est vide -- donc Koenig lookup s'applique mais ne trouve
rien. Ici, ce n'est pas le cas. L'ensemble des portées associées est

{ ::, C:: }

et Koenig lookup y trouvera (dans le contexte d'instanciation),
l'opérateur voulu.

| Peut-être mon erreur, c'est simplement que j'ai exterpolé quelque chose
| qui ne s'applique qu'aux types de base à tous les types dans le
| namespace global. (Dans §3.4.2/2, il dit « If T is a class type, [...].
| Its associated namespaces are the namespaces in which its associated
| classes are defined. » Est-ce que le namespace global compte ici ?

Oui, il compte, puisque comme tu l'appelles, c'est le _namespace_
global :-)

| Dans
| la mésure que ce n'est pas un « namespace » proprement dit)

3.3.5/3 dit que c'est un namespace.

-- Gaby
8 9 10 11 12