Bonjour,
J'ai un problème, qui dans sa version de base à déjà été écvoquer / partiellement résolu.
Ce problème de base est :
Comment partager l'instance d'un singleton entre une Dll et L'Exe si chaqun fait appel à getInstance dans son propre espace mémoire ?
voici un exemple de code source correspondant à ce problème :
Le template des singletons génériques :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#ifndef SINGLETON
#define SINGLETON
template <class S>
class Singleton
{
private:
static S * instance;
//static S Instance;
public:
/*
  static S & Get ()
  {
	 static S Instance; // règle le cas de l'ordre de construction
						// mais pas celui de l'ordre de destruction
	 return Instance;
  }
  */
  /**/
        static S * Get ()
        {
                if(!instance)
                        instance = new S;
                return instance;
        }
        /**/
};
//template <class S>
//S Singleton<S>::Instance;
template <class S>
S* Singleton<S>::instance = 0;
 
#endif
le singleton qui en dérive et en instancie par la même occasion (si on peut parler d'instanciation de template) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
 
using namespace std;
 
class TheSingleton
   : Singleton <TheSingleton> // magie!
{
   // sans ceci, le parent ne peut instancier son enfant
	friend class Singleton <TheSingleton>;
	TheSingleton (): m_Cur (0)
	{
		cout<<endl<<"Nouveau Singleton !!!"<<endl<<endl;
	};
 
	~TheSingleton(){};
 
	int m_Cur;
public:
	// vos services vont ici
	int Prochain()
	{
		return ++m_Cur; 
	};
 
	//static TheSingleton * Get() {return Singleton<TheSingleton>::Get();}
};
#endif
la classe principale de ma DLL exemple :
.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef TESTSINGLETONDLL
#define TESTSINGLETONDLL
#include "TheSingleton.h"
#include "dllImportExport.h"
#include <iostream>
 
using namespace std;
 
class DECLSPECIFIER_DLL TestSingletonDll
{
public:
	TestSingletonDll (){};	
 
	~TestSingletonDll(){};	
 
	int Next();
};
#endif
.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
#include "TestSingletonDll.h"
 
int TestSingletonDll::Next()
{
	return Singleton<TheSingleton>::Get()->Prochain();
	//return TheSingleton::Get()->Prochain();
}
la classe principale de mon executable :
.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef TESTSINGLETONMAIN
#define TESTSINGLETONMAIN
#include "TestSingletonDll.h"
#include <iostream>
 
using namespace std;
 
class TestSingletonMain   
{   
public:
	TestSingletonMain(){};
};
#endif
.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "TestSingletonMain.h"
int main ()
{
	int ij;
	TestSingletonMain* m = new TestSingletonMain();
	TestSingletonDll* d = new TestSingletonDll();
	cout << " courant : "<<d->Next()<<endl;
	cout << " courant : "<<d->Next()<<endl;
	cout<< " courant : "<<Singleton<TheSingleton>::Get()->Prochain()<<endl;
	//cout<< " courant : "<<TheSingleton::Get()->Prochain()<<endl;
 
	cin >> ij;
}
la sortie affichée :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
 
Nouveau Singleton !!!
 
 courant : 1
 courant : 2
 
Nouveau Singleton !!!
 
 courant : 1
Le problème ne semble donc pas résolu.

Finalement en exportant l'instanciation du singleton ça marche effectivement :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 
using namespace std;
 
//class TheSingleton;
//EXPIMP_TEMPLATE_DLL template class DECLSPECIFIER_DLL Singleton<TheSingleton>;
 
class DECLSPECIFIER_DLL TheSingleton
   : Singleton <TheSingleton> // magie!
{
   // sans ceci, le parent ne peut instancier son enfant
	friend class Singleton <TheSingleton>;
	TheSingleton (): m_Cur (0)
	{
		cout<<endl<<"Nouveau Singleton !!!"<<endl<<endl;
	};
 
	~TheSingleton(){};
 
	int m_Cur;
public:
	// vos services vont ici
	int Prochain()
	{
		return ++m_Cur; 
	};
 
	//static TheSingleton * Get() {return Singleton<TheSingleton>::Get();}
};
#endif
avec dllImportExport.h :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
#ifndef DLLIMPORTEXPORT_H
#define DLLIMPORTEXPORT_H
 
//macro to define if we export (from a DLL) or Import (from the Exe) without changing the header
#ifdef EXP_BLOCK // so we are in a DLL Block
#    define DECLSPECIFIER_DLL __declspec(dllexport)
#    define EXPIMP_TEMPLATE_DLL
#else // so we are in the Exe
#     define DECLSPECIFIER_DLL __declspec(dllimport)
#     define EXPIMP_TEMPLATE_DLL extern
#endif
#endif
Le problème de base est donc résolu.

La où je viens ici, c'est que contrairement a ce que j'ai présenté ici,
le problème est que dans ma véritable application, j'utilise des templates même en temps que singleton
(attention a ne pas confondre au singleton générique de base qui est lui aussi un template).
j'utilise quelque chose du genre :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
 
template <class A,class B>
class TheTemplatedSingleton
   : Singleton <TheTemplatedSingleton<A,B>> 
{
    ... 
}
Pour l'instant je suis arrivé a une solution "médiane"
Le problème que j'ai est que l'on ne peut pas vraiment exporter un template :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
template <class A, class B>
class DECLSPECIFIER_DLL TheTemplatedSingleton
   : Singleton <TheTemplatedSingleton<A,B>> // magie!
{
 ...
}
ça build bien la Dll, mais du point de vu de l'exe :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "TestSingletonMain.h"
int main ()
{
	int ij;
	TestSingletonMain* m = new TestSingletonMain();
	TestSingletonDll* d = new TestSingletonDll();
	cout << " courant : "<<d->Next<int,int>()<<endl;
	cout << " courant : "<<d->Next<int,int>()<<endl;
	//cout<< " courant : "<<Singleton<TheTemplatedSingleton<int,int>>::Get().Prochain()<<endl;
	cout<< " courant : "<< TheTemplatedSingleton<int,int>::Get().Prochain() <<endl;
 
	cin >> ij;
}
par contre le build ne finit pas, et débouche sur une erreur à l'étape de link :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
1>TestSingletonMain.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: static class TheTemplatedSingleton<int,int> & __cdecl TheTemplatedSingleton<int,int>::Get(void)" (__imp_?Get@?$TheTemplatedSingleton@HH@@SAAAV1@XZ) referenced in function _main
1>TestSingletonMain.obj : error LNK2019: unresolved external symbol "public: int __thiscall TestSingletonDll::Next<int,int>(void)" (??$Next@HH@TestSingletonDll@@QAEHXZ) referenced in function _main
bien sur si j'enlève les export/import :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
template <class A, class B>
class /*DECLSPECIFIER_DLL*/ TheTemplatedSingleton
   : Singleton <TheTemplatedSingleton<A,B>> // magie!
{
 ...
}
ça compile bien mais je me retrouve au problème initiale : duplication des instances :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
   Nouveau Singleton !!!
 
courant : 1
courant : 2
 
Nouveau Singleton !!!
 
courant : 1
finallement je suis obliger de simuler l'exportation du template pour passer l'étape de link.
Cela se fait en declarant et en exportant les différentes instance de template que l'on va utiliser :

TheTemplatedSingleton.cpp:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
#include "TheTemplatedSingleton.h"
template <class A, class B>
TheTemplatedSingleton<A,B>::TheTemplatedSingleton (): m_Cur (0)
	{
		cout<<endl<<"Nouveau Singleton<"<<typeid(A).name()<<","<<typeid(B).name()<< "> !!!"<<endl<<endl;
	}
 
template <class A, class B>
int TheTemplatedSingleton<A,B>::Prochain()
	{
		return ++m_Cur; 
	}
EXPIMP_TEMPLATE_DLL template class DECLSPECIFIER_DLL TheTemplatedSingleton<int,int>;
//EXPIMP_TEMPLATE_DLL template class DECLSPECIFIER_DLL Singleton<TheTemplatedSingleton<int,int>>;
et

TestSingletonDll.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
 
#include "TestSingletonDll.h"
 
template<class A, class B>
int TestSingletonDll::Next()
{
	//return Singleton<TheTemplatedSingleton<A,B>>::Get().Prochain();
	return TheTemplatedSingleton<A,B>::Get().Prochain();
}
 
EXPIMP_TEMPLATE_DLL template DECLSPECIFIER_DLL int TestSingletonDll::Next<int,int>();
En ce cas je peut builder l'executable car celui-ci n'utilise que l'instance du singleton template :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
TheTemplatedSingleton<int,int>
que je viens d'exporter explicitement (cette instance de TheTemplatedSingleton pour les type <int,int>)

et on peut voir que cela fonctionne effectivement :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
 
Nouveau Singleton<int,int> !!!
 
 courant : 1
 courant : 2
 courant : 3
Donc content ?
en fait NON car comme on le vois si on veut exporter un template, qui est singleton afin de n'avoir
qu'une seul instance (par instance de template!) partager entre la (les) Dll et l'exécutable,
il faut exporter explicitement TOUTES les instances possible du template que l'on serai a même d'utiliser au niveau de l'exécutable ...
bref plutôt contraignant ...

Existe t'il une solution/une parade a cela ? je suis preneur de toute information en ce sens