mardi 25 juillet 2017

C++11 factory using variadic template

I am working on a factory that can register and create classes with a different set a parameter types and numbers. I search over the internet and I managed to create this class:

template< typename Key, typename BaseClass >
class Factory {
    static_assert( std::has_virtual_destructor< BaseClass >::value,
        "BaseClass must have a virtual destructor" );
public:
    template< typename DerivedClass, typename ... Args >
    void register_creator( const Key& key )
    {
        static_assert( std::is_base_of< BaseClass, DerivedClass >::value,
            "DerivedClass must be a subclass of BaseClass" );
        static_assert( std::is_constructible< DerivedClass, Args... >::value,
            "DerivedClass must be constructible with Args..." );
        creators_.emplace(
            CreatorKey { key, create_function_type_index< Args... >() },
            reinterpret_cast< CreateFunc< > >( create_function_impl<
                DerivedClass, Args... > ) );
    }

    template< typename ... Args >
    std::unique_ptr< BaseClass > create(
        const Key& key,
         Args&&... args ) const
    {
        auto creator = creators_.find(
            { key, create_function_type_index< Args... >() } );
        if( creator != creators_.end() ) {
            return reinterpret_cast< CreateFunc< Args... > >( creator->second )(
                std::forward< Args>( args )... );
        } else {
            return {};
        }
    }

private:
    template< typename ... Args >
    static std::type_index create_function_type_index()
    {
        return {typeid( CreateFunc<Args...> )};
    }

    template< typename DerivedClass, typename ... Args >
    static std::unique_ptr< BaseClass > create_function_impl(
        const Args&... args )
    {
        return std::unique_ptr< BaseClass > { new DerivedClass {
            std::forward< const Args& >( args )... } };
    }

    template< typename ... Args >
    using CreateFunc = typename std::add_pointer< std::unique_ptr< BaseClass >( const Args&... ) >::type;
    using CreatorKey = std::pair< Key, std::type_index >;

    std::map< CreatorKey, CreateFunc< > > creators_;
};

My goal is to be able to run this kind of code:

class ___A___ {};
class ___B___ {};

class ___Base___ {
public:
    virtual ~___Base___() = default;
protected:
    ___Base___( ___A___ a, ___B___ b ) : a_( a ), b_( b ) {
    }
protected:
    ___A___ a_;
    ___B___ b_;
};

class ___Derived___: public ___Base___ {
public:
    ___Derived___( ___A___& a, ___B___& b ) : ___Base___( a, b ) {
    }
};

class ___Derived2___: public ___Base___ {
public:
    ___Derived2___( ___A___ a, ___B___ b ) : ___Base___( a, b ) {
    }
};

class ___Derived3___: public ___Base___ {
public:
    ___Derived3___( ___A___& a, ___B___ b ) : ___Base___( a, b ) {
    }
};

Factory< std::string, ___Base___ > factory;
factory.register_creator< ___Derived___, ___A___ &, ___B___& >( "Derived" );
factory.register_creator< ___Derived2___, ___A___, ___B___ >( "Derived2" );
factory.register_creator< ___Derived3___, ___A___ &, ___B___ >( "Derived3" );

___A___ a;
___B___ b;
auto D = factory.create( "Derived", a, b );
auto D2 = factory.create( "Derived2", ___A___(), ___B___() );
auto D3 = factory.create( "Derived3", a, ___B___() );

The registers works perfectly for both reference and value parameters but I cannot manage to instiate them using the creators. During my debugging, I saw that all the parameters where given by reference and never by value.

Aucun commentaire:

Enregistrer un commentaire