Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a variable number of arguments to constructors

Tags:

c++

c++11

I want to accomplish the following:

Entity e;
e.AddComponent<CPosition>(128, 128); //method should instantiate a new CPosition(128,128)
e.AddComponent<CSprite>(some, other, args); //etc

The important part is the AddComponent method. It should attempt to construct the generic type with the arguments passed. I believe C++11's variadic templates to forward the arguments to the constructor. However, I do not have access to this functionality yet (VS2010).

Does anyone have any idea on how to do this?

like image 225
Mohammed Hossain Avatar asked Dec 27 '22 15:12

Mohammed Hossain


2 Answers

Write a bunch of overloads, each taking a different number of parameters.

class Entity
{
public:
 template<typename T>
 void AddComponent() { component_ = new T(); }

 template<typename T, typename T1>
 void AddComponent(T1 t1) { component_ = new T(t1); }

 template<typename T, typename T1, typename T2>
 void AddComponent(T1 t1, T2 t2) { component_ = new T(t1, t2); }

 // etc
 ...
};
like image 150
Raymond Chen Avatar answered Jan 11 '23 01:01

Raymond Chen


Check how boost::container::vector::emplace_back is implemented: http://www.boost.org/doc/libs/1_51_0/boost/container/vector.hpp

It uses Boost.Preprocessor for auto-generation of functions taking different number of arguments. It generates some predefined number of functions.

As the result, you don't have to write each overload by hands. Instead, you can write your pattern only once.

For instance:

#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>

struct Entity
{
#define ENTITY_PP_PARAM_LIST(z, n, data) const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n)
#define ENTITY_PP_PARAM_PASS(z, n, data) BOOST_PP_CAT(p, n)

#define BOOST_PP_LOCAL_MACRO(n) \
    template<typename GenericType BOOST_PP_ENUM_TRAILING_PARAMS(n, typename P) > \
    void AddComponent(BOOST_PP_ENUM(n, ENTITY_PP_PARAM_LIST, _)) \
    { \
        something=new GenericType(BOOST_PP_ENUM(n, ENTITY_PP_PARAM_PASS, _)); \
    } \
    /**/

#define BOOST_PP_LOCAL_LIMITS (0, 3)
#include BOOST_PP_LOCAL_ITERATE()
};

After preprocessing expands to:

struct Entity
{
    template<typename GenericType  >
    void AddComponent()
    {
        something=new GenericType();
    }

    template<typename GenericType , typename P0 >
    void AddComponent( const P0 & p0)
    {
        something=new GenericType( p0);
    }

    template<typename GenericType , typename P0 , typename P1 >
    void AddComponent( const P0 & p0 , const P1 & p1)
    {
        something=new GenericType( p0 , p1);
    }

    template<typename GenericType , typename P0 , typename P1 , typename P2 >
    void AddComponent( const P0 & p0 , const P1 & p1 , const P2 & p2)
    {
        something=new GenericType( p0 , p1 , p2);
    }
};
like image 26
Evgeny Panasyuk Avatar answered Jan 11 '23 00:01

Evgeny Panasyuk