Reputation:
I've got 3 classes, like so:
template <typename RET, typename ARG1 = int, [...], typename ARG5 = int>
class FunctionPointer {
virtual operator()(ARG1, [...], ARG5);
};
template <typename RET, class TYPE, typename ARG1 = int, [...], typename ARG5 = int>
class ClassFunctionPointer : public FunctionPointer<RET, ARG1, [...], ARG5> {
// make it so that class functions fit here
};
template <typename RET, typename ARG1 = int, [...], typename ARG5 = int>
class GlobalFunctionPointer : public FunctionPointer<RET, ARG1, [...], ARG5> {
// make it so that non-member functions fit here
};
They are all overloaded so that every class may be instantiated with a variable number of arguments, meaning all of the following examples are valid:
GlobalFunctionPointer<void> a(&test1);
GlobalFunctionPointer<void, int> b(&test2);
ClassFunctionPointer<void, TestClass, int, char> c(testObject, &TestClass::test1);
ClassFunctionPointer<void, TestClass, int, char, std::string, float, SomeClass> d(testObject, &TestClass::test2);
But for all this, I wrote a lot of code, roughly 500 lines, see here. I find this is pretty ugly so I'm looking for a more elegant solution. Is there one at all?
(By the way, all the tangled code is meant to be the base for a more sophisticated event system.)
Upvotes: 1
Views: 148
Reputation: 9189
If your compiler do not have support of variadic templates, then you can try to use Boost.Preprocessor library for emulation.
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 function 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);
}
};
P.S. I agree with "Lightness Races in Orbit", consider to use boost/std ::function instead.
Upvotes: 1
Reputation: 385088
You're looking for C++11's variadic templates, invented for precisely this purpose.
Alternatively let a single template argument T
be an actual function type, then it can be void()
, void(int)
or void(int, char)
etc as your heart desires.
By the way, what is wrong with std::function<T>
(or boost::function<T>
)? This has all been solved already. :-)
Upvotes: 4