Finalement je pense que tu aurais pu utiliser des template, en fait, le principe est très simple :
-Tu enregistres chaque fonction et chaque classe de tes fonctions membres dans une factory en associant à chaque classe et à chaque fonction, un id unique que l'utilisateur (ou bien toi même) utilisera pour appeler la fonction à l'exécution.
Et tu fait une genre de méthode init() comme le fait SDL qui enregistre les fonctions appelée par ta librairie pour dessiner par exemple, bref tu enregistres ce que tu veux quoi. (Il faut passer le nom de la classe en paramètre template à la factory)
Le principe est fort similaire à celui des dll.
Bref moi c'est ce que j'utilise pour faire, un système de réflexion portable.
Ceci à l'avantage que peut importe le nom de la classe de base utilisée pour dessiner, l'utilisateur pourra choisir n'importe quelle type pour la classe de base à condition qu'il l'enregistre dans la factory à l'initialisation de SFML sinon il faudra renvoyer une exception.
Pour le bien tu devrais aussi utiliser std::function pour enregistrer les pointeurs sur tes fonctions de callback, ce qui donnerait quelque chose comme ceci :
#ifndef ODFAEG_FAST_DELEGATE_HPP
#define ODFAEG_FAST_DELEGATE_HPP
#include <functional>
#include <iostream>
#include "export.hpp"
#include "erreur.h"
#include <tuple>
#include <utility>
#include <memory>
/**
*\namespace odfaeg
* the namespace of the Opensource Development Framework Adapted for Every Games.
*/
namespace odfaeg {
/**
* \file fastDelegate.h
* \class IRefVal
* \brief Interface for the warppers to references, values and pointers.
* This class is used store references, pointers and values to pass to the callack's functions.
* \param T : the type of the value to wrap.
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template<class T>
struct IRefVal {
/**\fn
* \brief default constructor
*/
IRefVal()=default;
/**\fn T& get()
* \brief get the reference of the wrapped type.
* \return the reference of the wrapped type.
*/
virtual T& get() =0;
/**\fn std::unique_ptr<IRefVal<T>> clone() const = 0;
* \brief copy the wrapper.
* \return the copied wrapper.*/
virtual std::unique_ptr<IRefVal<T>> clone() const = 0;
/**\fn destructor*/
virtual ~IRefVal(){}
protected:
/**\fn IRefVal(const IRefVal&)
* \brief constructor, pass the reference to wrap.
* \param const IRefVal& : the reference to wrap.
*/
IRefVal(const IRefVal&){}
/** \fn IRefVal& operator=(const IRefVal&)
* \brief affector.
* \param const IRefVal& : the wrapper to affect.
* \return the affected wrapper.*/
IRefVal& operator=(const IRefVal&)
{ return *this; }
};
/**
* \file fastDelegate.h
* \class Ref
* \brief Warp a reference. (Use std::reference_wrapper so we can pass a reference with std::ref)
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template<class T>
struct Ref : IRefVal<T> {
/**
*\fn Ref(const std::reference_wrapper<T>& r)
*\brief Constructor : pass an std::reference_wrapper to the wrapper.
*\param std::reference_wrapper<T>& r : the reference_wrapper.
*/
Ref(const std::reference_wrapper<T>& r)
: ref(r)
{}
/**
* \fn T& get()
* \brief return a reference to an object.
* \return T& the reference to the object.
*/
T& get()
{ return ref.get(); }
/**
* \fn std::unique_ptr<IRefVal<T>> clone() const
* \brief copy the reference wrapper.
* \return std::unique_ptr<IRefVal<T>> : the cloned wrapper.
*/
std::unique_ptr<IRefVal<T>> clone() const
{ return std::make_unique<Ref>(*this); }
private:
std::reference_wrapper<T> ref; /**> the std::reference_wrapper which warp the reference.*/
};
/**
* \file fastDelegate.h
* \class Val
* \brief Warp a value.
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template<class T>
struct Val : IRefVal<T> {
/**\fn Val(const T& t)
* \brief pass a value to the wrapper.
* \param const T& t : the value to pass.
*/
Val(const T& t)
: val(t)
{}
/** \fn
* \brief return the value
* \return T& : return the value.
*/
T& get()
{ return val; }
/**
* \fn std::unique_ptr<IRefVal<T>> clone() const
* \brief copy the value wrapper.
* \return std::unique_ptr<IRefVal<T>> : the cloned wrapper.
*/
std::unique_ptr<IRefVal<T>> clone() const
{ return std::make_unique<Val>(*this); }
private:
T val; /**> T val : keep the value of the wrapper.*/
};
/**
* \file fastDelegate.h
* \class Ref
* \brief Warp a pointer.
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template<class T>
struct Pointer : IRefVal<T> {
/**\fn Pointer(const T* t)
* \brief pass a pointer to the wrapper.
* \param const T* t : the pointer to pass.
*/
Pointer(const T* t)
: pointer(t)
{}
/** \fn
* \brief return the pointer of the wrapper.
* \return T& : return the pointer.
*/
T& get()
{ return pointer; }
/**
* \fn std::unique_ptr<IRefVal<T>> clone() const
* \brief copy the pointer wrapper.
* \return std::unique_ptr<IRefVal<T>> : the cloned wrapper.
*/
std::unique_ptr<IRefVal<T>> clone() const
{ return std::make_unique<Pointer<T>>(*this); }
private:
T pointer; /**> T pointer : keep the pointer of the wrapper.*/
};
/**
* \file fastDelegate.h
* \class RefVal
* \brief Wrap a pointer, a value or a reference an keep a pointer to the generic wrapper.
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template<class T>
struct RefVal {
/**
* \fn RefVal (const T& t)
* \brief constructor : construct a wrapper to a value
* \param const T& t : the value to
*/
RefVal(const T& t)
: rv(std::make_unique<Val<T>>(t))
{}
RefVal(const std::reference_wrapper<T>& r)
: rv(std::make_unique<Ref<T>>(r))
{}
RefVal(const T*& p)
: rv(std::make_unique<Pointer<T>>(p))
{}
RefVal(const RefVal& rhs)
{
rv = rhs.rv->clone();
}
RefVal& operator=(const RefVal& rhs)
{ rv=rhs.rv->clone(); return *this; }
T& get() const
{ return rv->get(); }
private:
std::unique_ptr<IRefVal<T>> rv;
};
//Classe de trait pour déterminer le type à stocker
//(Interne) Cas général
template<class T>
struct ToStoreImpl
{ using type = T; };
template<class T>
struct ToStoreImpl<std::reference_wrapper<T>>
{ using type = T; };
template<class T>
struct ToStore
: ToStoreImpl<std::remove_reference_t<T>>
{};
template<class T>
using ToStore_t = typename
ToStore<T>::type;
template<class R, class C, class... ArgT>
struct DynamicWrapper {
DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf){}
template<class O, class... ArgU>
R operator()(O* o, ArgU&&... arg) const
{
if(dynamic_cast<C*>(o))
return (dynamic_cast<C*>(o)->*pfunc)(std::forward<ArgU>(arg)...);
throw Erreur(0, "Invalid cast : types are nor polymorphic!", 1);
}
private:
R (C::*pfunc)(ArgT...);
};
template<class F>
class DynamicFunction;
template<class R, class... ArgT>
class DynamicFunction<R(ArgT...)>
: std::function<R(ArgT...)>
{
using Base = std::function<R(ArgT...)>;
public:
template<class F>
DynamicFunction(F&& f) : Base(std::forward<F>(f))
{}
template<class C, class... ArgU>
DynamicFunction(R (C::*pf)(ArgU...))
: Base(DynamicWrapper<R,C,ArgU...>(pf))
{}
using Base::operator();
};
template<class R>
struct Delegate {
Delegate() =default;
virtual std::unique_ptr<Delegate> clone() const = 0;
virtual R operator()() = 0;
virtual ~Delegate(){}
protected:
Delegate(const Delegate&){}
Delegate& operator=(const Delegate&)
{ return *this; }
};
template<class R, class... ArgT>
struct FastDelegateImpl : Delegate<R> {
template<class F, class... ArgU>
FastDelegateImpl(F&& f, ArgU&&... arg)
: func(std::forward<F>(f))
, param(std::forward<ArgU>(arg)...)
{}
std::unique_ptr<Delegate<R>> clone() const
{ return std::make_unique<FastDelegateImpl>(*this); }
R operator()()
{ return call(std::make_index_sequence<sizeof...(ArgT)>()); }
template<class... ArgU>
void setParams(ArgU&&... arg)
{ param=std::make_tuple(std::forward<ArgU>(arg)...); }
private:
template<std::size_t... I>
R call(std::index_sequence<I...>)
{ return func(std::get<I>(param).get()...); }
std::function<R(ArgT&...)> func;
std::tuple<RefVal<ArgT>...> param;
};
template<class R>
struct FastDelegate {
FastDelegate() = default;
template<class F, class... Arg>
FastDelegate(F&& f, Arg&&... arg) :
delegate(std::make_unique
<FastDelegateImpl<R,ToStore_t<Arg>...>>
(std::forward<F>(f),std::forward<Arg>(arg)...)
)
{}
FastDelegate(FastDelegate& rhs)
: delegate(rhs.delegate->clone())
{}
FastDelegate(const FastDelegate& rhs)
: delegate(rhs.delegate->clone())
{}
FastDelegate(FastDelegate&& rhs) =default;
FastDelegate& operator=(const FastDelegate& rhs)
{ return operator=(FastDelegate(rhs)); }
FastDelegate& operator=(FastDelegate&&) =default;
R operator()() const
{ return (*delegate)(); }
template<class... Arg>
void setParams(Arg&&... arg)
{
using StaticType =
FastDelegateImpl<R,ToStore_t<Arg>...>*;
static_cast<StaticType>(delegate.get())->setParams(std::forward<Arg>(arg)...);
}
private:
std::unique_ptr<Delegate<R>> delegate;
};
}
#endif
//fichier fabrique.h
#ifndef ODFAEG_FACTORY_HPP
#define ODFAEG_FACTORY_HPP
#include <map>
#include <string>
#include "export.hpp"
#include "fastDelegate.h"
/**\file factory.h
* \brief This file register types of derived objects
* and instanciate the polymorphic objects of the right type with the given type id.
* There are two factories
* The static factory (The class Factory) which evaluate objects and functions at compile time.
* The dynamic factory (The class BaseFactory) which evaluate objects and functions at runtime.
* The dynamic factory avoids to have a reflexion system which is impossible to make in c++ without a lot of macros.
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
/********************************************************************************************************************/
/**\fn
* \brief This is an helper function like macro which register a derived type in the dynamic factory.
* \param ID : an ID which is associate to a derived type.
* \param BASE : the base type of the derived class.
* \param DERIVED : the derived type of the derived class.
*/
#define REGISTER_TYPE(ID, BASE, DERIVED) \
{ \
DERIVED *derived##ID = nullptr; \
odfaeg::Allocator<BASE> allocator##ID; \
BASE*(odfaeg::Allocator<BASE>::*f##ID)(DERIVED*) = &odfaeg::Allocator<BASE>::allocate<DERIVED>; \
odfaeg::FastDelegate<BASE*> allocatorDelegate##ID(f##ID, &allocator##ID, derived##ID); \
odfaeg::BaseFact<BASE>::register_type(typeid(DERIVED).name(), allocatorDelegate##ID); \
}
/**fn
* \brief This is an helper function like macro which register a function in the dynamic factory.
* \param ID : an ID which is associate to a derived type.
* \param funcName : the name of the derived class member's function to register.
* \param SID : an ID associated to the argument list of the member's function to register.
* \param BASE : the base type of the derived class.
* \param DERIVED : the derived type of the derived class.
* \param SIGNATURE : the signature of the function to register.
*/
#define REGISTER_FUNC(ID, funcName, SID, BASE, DERIVED, SIGNATURE, args...) \
{ \
REGISTER_TYPE(ID, BASE, DERIVED) \
void(DERIVED::*f##ID##funcName##SID)SIGNATURE = &DERIVED::vt##funcName; \
odfaeg::FastDelegate<void> delegate##ID##funcName##SID (f##ID##funcName##SID, args); \
odfaeg::BaseFact<BASE>::register_function(typeid(DERIVED).name(), #funcName, #SID, delegate##ID##funcName##SID); \
}
/**
*\namespace odfaeg
* the namespace of the Opensource Development Framework Adapted for Every Games.
*/
namespace odfaeg {
/**\class Factory
* \brief This class register types of derived objects
* and instanciate the polymorphic objects of the right type with the given type id.
* This is a static factory, it means that the id is defined at compile time.
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template <class O, class K = std::string>
class Factory {
private :
static std::map<K, O*> m_map;
public:
static void Register (K key, O* object);
O* Create (const K& key);
};
/**\class Allocator
* \brief this struct allocate an object of a derived type and return a pointer of the base type.
* \param B : the base type.
*/
template <typename B>
struct Allocator {
/**\fn allocate(D*)
* \brief this function allocates an object of a derived type and return a pointer of the base type.
* \param D : the derived type.
* \return B* : a pointer to the base type.
*/
template <typename D>
B* allocate(D*) {
return new D();
}
};
/**\class BaseFactory
* \brief This class register types of derived objects
* and instanciate the polymorphic objects of the right type with the given type id.
* This is a dynamic factory, it means that the id is defined at runtime time with RTTI infos.
* So you must provide the id with typeid(object).name().
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template <typename B>
class BaseFactory {
public :
/**
* \fn void register_type (std::string typeName, FastDelegate<B*> allocatorDelegate)
* \brief register a type into a factory, if the type isn't already registered.
* \param std::string typeName : the name of the type to register.
* \param a callback function to an allocator, to return a pointer of the base class which point
* to the derived object.
*/
static void register_type(std::string typeName, FastDelegate<B*> allocatorDelegate) {
typename std::map<std::string, FastDelegate<B*>>::iterator it = types.find(typeName);
if (it == types.end()) {
types[typeName] = allocatorDelegate;
}
}
/** \fn void register_function(std::string typeName, std::string funcName, std::string funcArgs, FastDelegate<void> delegate)
* \brief register a member function of a class type into the factory.
* \param std::string typeName : the type name of the class containing the member function to register.
* \param std::string funcName : the name of the function to register.
* \param std::string funcArgs : the name of the types of the member function's argument list to register.
* \param FastDelegate<void> delegate : a callback function of the registered member function. (only funcions returing void can be registered!)
*/
static void register_function(std::string typeName, std::string funcName, std::string funcArgs, FastDelegate<void> delegate) {
typename std::map<std::string, FastDelegate<void>>::iterator it = functions.find(typeName+funcName+funcArgs);
if (it == functions.end())
functions[typeName+funcName+funcArgs] = delegate;
}
/** \fn void callFunction(std::string typeName, std::string funcName, std:string fincArgs, A&&... args)
* \brief call a registered function of the factory, throw an error if the function isn't registered.
* \param std::string typeName : the type name of the class containing the member function.
* \param std::string funcName : the name of the member function.
* \param std::string funcArgs : the name of the types of the member function's argument list to call.
* \param A&& args.... : the value of the arguments to pass to the callback's member function. (object + arguments)
*/
template <typename... A>
static void callFunction(std::string typeName, std::string funcName, std::string funcArgs, A&&... args) {
typename std::map<std::string, FastDelegate<void>>::iterator it = functions.find(typeName+funcName+funcArgs);
if (it != functions.end()) {
it->second.setParams(std::forward<A>(args)...);
(it->second)();
} else {
throw Erreur(0, "Unregistred function exception!", 1);
}
}
/** \fn B* create (std::string typeName)
* \brief return a pointer of the base class of an object which point to an object of a derived type.
* this function call a callback function to an allocator function to allocate the object.
* \param the typeName of the type to allocate.
* \return B* a pointer of a base class which'll point to the allocated object.
*/
static B* create (std::string typeName) {
typename std::map<std::string, FastDelegate<B*>>::iterator it = types.find(typeName);
if (it != types.end()) {
return (it->second)();
}
throw Erreur(0, "Unregistred type exception!", 1);
}
/** \fn std::string getTypeName (B* type)
* \brief return the type name of a base object.
* \param B* type : a pointer to the type to check the dynamic type name.
* \return the dynamic type name of the passed object*/
static std::string getTypeName (B* type) {
typename std::map<std::string, FastDelegate<B*>>::iterator it = types.find(typeid(*type).name());
if (it != types.end())
return it->first;
}
private :
static std::map<std::string, FastDelegate<B*>> types; /**> An std::map which store the typeName and a callback's function to an allocator of the registered types*/
static std::map<std::string, FastDelegate<void>> functions; /**> An std::map which store the signature and a callback's function to the registered member's functions.*/
};
template <typename B>
std::map<std::string, FastDelegate<B*>> BaseFactory<B>::types = std::map<std::string, FastDelegate<B*>>();
template <typename B>
std::map<std::string, FastDelegate<void>> BaseFactory<B>::functions = std::map<std::string, FastDelegate<void>>();
}
#endif
Ensuite tu n'as plus qu'à faire une fonction SFML_Init() pour enregistrer toutes les classes et fonctions template utiliser par SFML.
Donc je pense que tu pourrais améliorer SFML à l'avenir, et utiliser le c++14.
(Ne t'inquiète pas pour la compatibilité, normalement tout les PC supportent gcc4.9 et d'aileurs c'est la version de gcc qu'on devrait tous utiliser pour des raisons de sécurité, et éviter les nombreux memory leaks et problème d'UB présent encore dans certaines libs écrite en C utilisant SFML mais aussi parfois dans SFML.