#include <iostream>
#include <memory>
#include <typeindex>
#include <vector>
#include <utility>
using namespace std;
// Predefine template delegate factory
template < typename R, typename... Args >
class brGenericDelegate ;
// C++11 template alias to announce functor definition
template < typename R, typename... Args >
using brGenericDelegateType = std::function< std::shared_ptr<R>(Args...) > ;
class brDelegate
{
protected:
brDelegate(){}
public:
virtual ~brDelegate() = default ;
template < typename R, typename... Args >
static std::shared_ptr<brDelegate> create( typename brGenericDelegate<R,Args...>::functor func )
{
return std::make_shared<brGenericDelegate<R,Args...>>(func) ;
}
template < typename R, typename... Args >
std::shared_ptr<R> run( Args... args ) const
{
using derived_type = brGenericDelegate<R,Args...> ;
return dynamic_cast< const derived_type& >(*this)(args...) ;
}
template < typename R, typename... ARGS >
bool isSignatureEquals(void) const
{
bool isEquals = false;
if(this->getReturnType() == typeid(R)){
if(this->getNumberOfArguments() == sizeof...(ARGS)){
std::vector<std::type_index> args;
args.insert(args.end(), {typeid(ARGS)...});
if(args == this->getArgTypes()){
isEquals = true;
}
}
}
return isEquals;
}
protected:
virtual std::type_index getReturnType(void) const = 0;
virtual unsigned int getNumberOfArguments(void) const = 0;
virtual const std::vector<std::type_index>& getArgTypes(void) const = 0;
};
template < typename R, typename... Args >
class brGenericDelegate : public brDelegate
{
public:
using functor = brGenericDelegateType< R, Args... >;
brGenericDelegate( functor f ) : fn(f) {
m_args.insert(m_args.end(), {typeid(Args)...});
}
std::shared_ptr<R> operator() ( Args... args ) const
{
return fn(args...) ;
}
std::type_index getReturnType(void) const {
return typeid(R);
}
unsigned int getNumberOfArguments(void) const {
return sizeof...(Args);
}
const std::vector<std::type_index>& getArgTypes() const{
return m_args;
}
private:
const functor fn ;
std::vector<std::type_index> m_args;
};
// Test interface 1
class Gun
{
public:
Gun(){}
virtual ~Gun(){}
virtual std::string getName(void) const = 0;
virtual std::string getType(void) const = 0;
virtual double getCaliber(void) const = 0;
};
class MachineGun : virtual public Gun
{
public:
MachineGun(double caliber, const std::string name)
:m_caliber(caliber), m_name(name){}
virtual ~MachineGun(){}
virtual std::string getName(void) const {
return m_name;
}
virtual std::string getType(void) const {
return "projectile";
}
virtual double getCaliber(void) const {
return m_caliber;
}
private:
double m_caliber;
std::string m_name;
};
class Armament
{
public:
Armament(std::shared_ptr<Gun> primary)
:m_primary(primary){}
~Armament(){}
const std::shared_ptr<Gun> getPrimaryWeapon(void){
return m_primary;
}
const std::shared_ptr<Gun> getSecondaryWeapon(void){
return m_secondary;
}
private:
std::shared_ptr<Gun> m_primary = nullptr;
std::shared_ptr<Gun> m_secondary = nullptr;
};
class brImage;
class brTexture
{
public:
enum eTextureType{
TYPE_TEXTURE_2D = 1,
TYPE_TEXTURE_CUBEMAP = 2
};
public:
brTexture(eTextureType type){}
virtual ~brTexture(){}
virtual void bind(unsigned int unit) = 0;
virtual void unbind(unsigned int unit) = 0;
virtual void update(void) = 0;
};
class brGL3Texture : virtual public brTexture
{
public:
brGL3Texture(brTexture::eTextureType type):brTexture(type){}
virtual ~brGL3Texture(){}
void bind(unsigned int unit){}
void unbind(unsigned int unit){}
void update(void){}
protected:
int m_textureID;
};
class brGL3TextureSampler
{
public:
brGL3TextureSampler(std::shared_ptr<brTexture> texture)
:m_texture(texture){}
virtual ~brGL3TextureSampler(){}
private:
void init(void){}
void bindTextureSampler(void){}
std::shared_ptr<brTexture> m_texture = nullptr;
};
std::shared_ptr<brDelegate> delegate = nullptr;
// Perfect forwarding test function
template <typename R, typename ... ARGS>
std::shared_ptr<R> resolve(ARGS&& ... args)
{
return delegate->run<R, ARGS...>(std::forward<ARGS>(args)...);
}
int main() {
auto gun_factory = brDelegate::create<MachineGun, double, std::string>
([] (double caliber, const std::string& name) -> std::shared_ptr<MachineGun>
{ return std::make_shared<MachineGun>(caliber, name); });
auto gun = gun_factory->run<MachineGun, double, std::string>(50.0, "BAR");
delegate = brDelegate::create<Armament, std::shared_ptr<Gun>>
([] (std::shared_ptr<Gun> primary) -> std::shared_ptr<Armament> { return std::make_shared<Armament>(primary); });
auto test = resolve<Armament, std::shared_ptr<Gun>>(gun);
auto tex_factory = brDelegate::create<brTexture, brTexture::eTextureType>
([] (brTexture::eTextureType type) -> std::shared_ptr<brTexture>
{ return std::make_shared<brGL3Texture>(type); });
auto texture = std::make_shared<brGL3Texture>(brTexture::TYPE_TEXTURE_2D);
//auto texture = tex_factory->run<brTexture, brTexture::eTextureType>(brTexture::TYPE_TEXTURE_2D);
delegate = brDelegate::create<brGL3TextureSampler, std::shared_ptr<brTexture>>
([] (std::shared_ptr<brTexture> tex) -> std::shared_ptr<brGL3TextureSampler>
{ return std::make_shared<brGL3TextureSampler>(tex); });
auto test1 = resolve<brGL3TextureSampler, std::shared_ptr<brTexture>>(texture);
return 0;
}