Newsgroup: it.comp.lang.c++
Titolo: namespace

Ciao a tutti,
mi sono imbattuto in un piccolo problema ma che non riesco a risolvere.
Sto sviluppando un'applicazione e vorrei utilizzare un file per ogni 
classe (bhe più o meno...) ed accorparle sotto un unico namespace.
Il linker però si ribella...
Esempio:
//file foo.h
namespace NS
{
	int x;
	class foo
	{
	public:
		foo(void);
		~foo(void);
	};
}
//file good.h
namespace NS
{
	foo f; //errore del linker
	class good
	{
	public:
		good(void);
		~good(void);
	};
}
//file main.cpp
#include "foo.h"
#include "good.h"
void main()
{
	foo x;
	good y;
}
Quando compilo il linker ovviamente si chiede che cos'è foo... ho 
provato a mettere un #include "foo.h" nel file good.h ma in questo modo 
i simboli vengono ridefiniti. Per evitare questo ho messo anche la 
direttiva #pragma once ma non è servito a nulla.
Qualche suggerimento?

Diego Chiodini ha scritto:

NS::foo dovrebbe risolvere il problema ( o equivalente direttiva using
namespace NS ) .
Il problema dell'inclusione lo risolvi includendo il codice del .h tra
direttive ifdef
#ifndef __ABCD__
#define __ABCD__
il tuo codice
#endif
Ovviamente ABCD deve differire per ogni file .h

 
Qui scrivi
          extern foo f; // dichiarazione, non definizione
Poi, in una sola unità di compilazione (good.cpp, probabilmente) metterai 
(sempre nel namespace NS) la definizione.
         foo f; 
Tutte le unità che useranno 'f', dovranno #includere 'good.h'.
Ad ogni modo, in realtà il problema non si pone, perché 'f' è una variabile 
globale, che è Male e che perciò va eliminata tout-court. :)
Max
 

 void main()
 >
non ha a che fare col tuo problema,
comunque te lo faccio notare lo stesso:
http://www.emagsoftware.it/faqcpp.htm#18a
-- 
Simone.


"Egon faccio sempre confusione tra bene e male, cosa intendi per male?"
Una bambolina a chi indovina la citazione!
A me interessa poter richiamare le classi del namespace da un file 
all'altro; per questo ho risolto con #ifndef ecc... (grazie Bruno).
A dire il vero avevo già provato a fare così ma sbagliavo posizione 
degli #ifndef... ma per questo diamo la colpa al caldo ;)
Adesso però sono curioso di sapere perchè non funziona con extern...
al momento ho un errore di *compilazione* e non del linker... mha!
//file foo.h
#ifndef _FOO_
#define _FOO_
namespace NS
{
	//int x;
     class foo
     {
     public:
         foo(void);
         ~foo(void);
     };
}
#endif
//file good.h
#ifndef _GOOD_
#define _GOOD_
//#include "foo.h"
//per farlo funzionare elimino il commento e a parola extern
namespace NS
{
     class good
     {
     public:
         good(void);
         ~good(void);
	extern	foo f;
     };
}
#endif
//file main.cpp
#include "foo.h"
#include "good.h"
using namespace NS;
void main()
{
     foo k;
     good y;
}

 Una bambolina a chi indovina la citazione!
Ghostbuster! Quando Peter Venkman chiede a Egon Spengler del perchè non 
debbano incrociare i flussi ^_^
......e la bambolina?
Scusate l'ot

 }
Nel codice che hai mostrato nel primo messaggio 'f' era una variabile 
globale nel namespace 'NS'. Ora hai spostato la dichiarazione nel corpo 
della definizione di 'foo', quindi 'extern' non è più applicabile. Se 'f' 
dev'essere un membro static di 'good', la dichiari con 'static' e poi la 
definisci in una unità di compilazione (good.cpp, ad esempio). Altrimenti, 
lasci 'estern', ma sposti la dichiarazione fuori dal corpo di 'foo'. Se 
togli 'extern' e la lasci lì, diventa un membro ordinario (non static, 
cioè) di 'good'.
Max


Che stress questa storia dei namespace ;)
Ho messo foo globale inizialmente per semplificare le classi rispetto 
quelle che uso, così da chiarirmi le idee ma con scarso esito...
ora riporto le classi effettive.
//file GameRender.h
#pragma once
#ifndef _GAME_RENDER_
#define _GAME_RENDER_
#include "GameStructure.h"
namespace Game
{
	namespace Render
	{
		class RenderManager
		{
		public:
			void Render();
		private:
			ListManager *pList;
		};
	}
}
using namespace Game::Render;
#endif
//file GameStructure.h
#pragma once
#ifndef _GAME_STRUCTURE_
#define _GAME_STRUCTURE_
namespace Game
{
	namespace Structure
	{
		.
		.
		.
		class ListManager
		{
		public:
			void AddGroup();
				.
				.
				.
 
		};
	}
}
using namespace Game::Structure;
#endif
//file GameRender.cpp
#include ".\gamerender.h"
void RenderManager::Render()
{
	pList->AddGroup(); //ERRORE LNK2019
}
Ho cercato di ripulire al meglio il codice.
Se tento di compilare ricevo unresolved external symbol.
L'implementazione della classe ListManager è su un file chiamato 
GameStructure.cpp incluso nel progetto (VS.NET03).
Se non richiamo nessuna procedura il problema non si pone (ma anche il 
programma diventà un po' inutile ;)
Non riesco a capire dove commetto l'errore... gli ho passato gli header, 
ad ognuno di questi è associata a sua unità di compilazione (tramite 
VS), cosa può volere di più dalla vita un compilatore? Un Lucano?
Grazie per la pazienza!

<snip>

per prima cosa è brutto quel using ..... al termine del file include, rendi 
inutile l'uso del namespace.
Se vuoi usarlo per evitare di scrivere tutto il naming mettilo nel file 
.cpp.
La classe ListManager è nel namespace Game::Structure quindi devi anteporlo 
quando lo definisci.
Terza cosa, spero che lo allochi pList prima di usarlo
Ciao 

 
Naturalmente ;)
Mi sono accorto che in realtà il problema è da un'altra parte.
Ho provato a chiamare altre funzioni (*non* inline) della stessa classe 
e tutto andava bene... l'errore (unresolved external symbol) viene 
generato quando chiamo funzioni inline.
La definizione di AddGroup() in GameStructure.cpp è
inline void ListManager::AddGroup(){...}
ho provato a cercare su google ma ho trovato argomenti simili per i 
template ma non sono riuscito a risolvere.
Ciao!
PS: l'argomento del thread è di fatto cambiato ma non voglio intasare il 
NG creandone uno nuovo per lo stesso problema.


usata così devi dichiararla all'interno del namespace, altrimenti devi 
anteporgli il naming.
es. inline void Game::Structure::ListManager::AddGroup(){...}
Visto che è inline, quindi probabilmente saranno poche righe di codice, fai 
prima una prova e definiscila direttamente insieme alla dichiarazione. In 
quel modo non dovrebbe darti errore. 

 dichiarazione. In quel modo non dovrebbe darti errore.
Argh! Penso di avere seri problemi di comunicazione!
Spero che sia dovuto al fatto che mi sveglio alle 8 di mattina per 
programmare anche quando sono in ferie...
Chiaramente nel file .cpp ho messo
using namespace Game::Structure;
Messa dentro il file .h compila correttamente ma la curiosità rimane!
scrivere
class foo
{
	void bar(){...}
}
e scrivere
class foo
{
	int bar();
}
inline void foo::bar(){...}
è equivalente. Solo che è più "corretto/stiloso" non implementare la 
funzione inline nell'header. Ma perchè diamine non mi trova il codice 
nel secondo caso?!?
Ciao!


non ho capito se stai implementando l'inline nel .cpp (sbagliato) o nel .h 
(giusto).
Comunque definisci l'inline subito dopo la dichiarazione della classe e deve 
funzionare. 

 deve funzionare.
Ora, nel codice reale, funziona perchè ho implementato le funzioni nel 
file .h, ma non capisco perchè se le implemento nel file .cpp il linker 
mi da errore.
Leggendo su internet e sul qualche libro non è sbagliato dichiarare una 
funzione in un file .h in questo modo
class foo
{
     void bar();
}
  e poi implementarla come inline in un file .cpp, in questo modo
inline void foo::bar(){...}
Dovrebbe essere equivalente ad implementare la funzione direttamente nel 
file .h

 file .h
inline significa che il compilatore, anziché inserire una chiamata al 
metodo, inserisce direttamente il codice della funzione.
Se nascondi l'implementazione in un file .cpp non può essere vista da un 
altro file .cpp e quindi come fa a scriverci il codice?
Il compilatore vede solo, nel file include, la dichiarazione di un metodo 
della classe che sarà definita poi in qualche modulo.
All'opposto, se definisci una funzione 'non inline' (e fuori della classe) 
in un file header, se includi il file .h in due .cpp avrai l'errore di 
funzione già definita.

 
Ok ho risolto l'arcano consultando il buon Stroustrup.
Avevo dato per scontato che l'implementazione della funzione inline 
potesse essere messa anche su un altro file.. e invece no ;)
Ok anche oggi ho imparato qualcosa di nuovo, grazie a tutti!
Ciao!