Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Structure or Class with variable number of members

I want to create a structure/class with a variable number of class members which could be decided at compilation stage (like done in template metaprogramming)

Example : Its hypothetical in which both type and variable names are to be specified like Type T1 variable name should be varName1 and so on .....

template <class T1 (varName1) >
MyClass
{
     T1 varName1;

}

template <class T1 (varName1), class T2 (varName2) >
MyClass
{
     T1 varName1;
     T1 varName2;
}

and in main code which can be declared like following or some other way in which type and name can be specified

MyClass Obj;

and MyClass::somefunc() can access variable names as follows

MyClass::somefunc()
{
     std::cout <<" abc value : " << abc << std::endl;
     std::cout <<" xyz value : " << xyz << std::endl;
}

Is this possible via template metaprogramming in C++ to have both type and variable name specification ?

like image 712
Pardeep Avatar asked Dec 17 '22 21:12

Pardeep


1 Answers

With template metaprogramming and little preprocessing, it is possible to achieve a syntax close to desirable:

//one has to "declare" once an attribute name to be able to use
//it later in any number of class declarations
DECLARE_ATTRIBUTE_NAME(foo);
DECLARE_ATTRIBUTE_NAME(quux);
DECLARE_ATTRIBUTE_NAME(bar);
DECLARE_ATTRIBUTE_NAME(baz);

//pass types and declared attribute names, separated by comma
typedef TupleWithNamedMembers<int, foo,
                              float, quux,
                              double, bar,
                              char, baz
                        > MyTuple;
//extra call to macro "MAKE_TUPLE" can be avoided, see below
class MyConstruct: public MAKE_TUPLE(MyTuple)
{ };

//usage
int main(int argc, char* argv[])
{
    MyConstruct construct;
    construct.foo = 3;
    construct.bar = 5.6;
    construct.quux = 8.9;
    construct.baz = 'h';
    return 0;
}

The implementation:

#ifndef TupleWithNamedMembersH
#define TupleWithNamedMembersH
//---------------------------------------------------------------------------

#include <Loki/typelist.h>
#include <Loki/HierarchyGenerators.h>

template<class T, int a>
struct attribute
{
};

//the generated id is not really unique in all cases
//one should provide better implementation
#define GENERATE_UNIQ_ID(name) ((sizeof(#name)<<16)|__LINE__)

//specializations of the struct "attribute" act like compile-time map between
//a name ID and an attribute name 
#define DECLARE_ATTRIBUTE_NAME_IMPL(name, id) \
    enum { id = GENERATE_UNIQ_ID(name) }; \
    template<class T> \
    struct attribute<T,id> \
    {\
        T name;\
    };
#define DECLARE_ATTRIBUTE_NAME(name)\
    DECLARE_ATTRIBUTE_NAME_IMPL(name, name)

//helps to pass pair of type and name ID as a single type
template<class T, int i>
struct pair
{
    static const int val = i;
    typedef T type;
};

//unpacks compile-time data from PairT and inherits attribute
//with name selected by ID
template<class PairT>
class holder: public attribute<typename PairT::type,PairT::val>
{    };

//turns template arguments into Loki::TypeList
template
<
    typename T1  = Loki::NullType, int i1 = 0, typename T2  = Loki::NullType, int i2 = 0,
    typename T3  = Loki::NullType, int i3 = 0, typename T4  = Loki::NullType, int i4 = 0,
    typename T5  = Loki::NullType, int i5 = 0, typename T6  = Loki::NullType, int i6 = 0,
    typename T7  = Loki::NullType, int i7 = 0, typename T8  = Loki::NullType, int i8 = 0,
    typename T9  = Loki::NullType, int i9 = 0, typename T10 = Loki::NullType, int i10 = 0
>
struct TupleWithNamedMembers
{
public:
    typedef Loki::TL::MakeTypelist<pair<T1,i1>, pair<T2,i2>,
                                   pair<T3,i3>, pair<T4,i4>,
                                   pair<T5,i5>, pair<T6,i6>,
                                   pair<T7,i7>, pair<T8,i8>,
                                   pair<T9,i9>, pair<T10,i10>
                         >::Result Result;
};

//this macro is required because of internal compiler error that I encounter
//Loki::GenScatterHierarchy makes a class inherit every attribute from the type list
#define MAKE_TUPLE(types) Loki::GenScatterHierarchy<types::Result, holder>

#endif //end of "TupleWithNamedMembers.h"

Notes: The MAKE_TUPLE macro should be a metafunction, if your compiler is OK with the code below:

template
<
    typename T1  = Loki::NullType, int i1 = 0, typename T2  = Loki::NullType, int i2 = 0,
    typename T3  = Loki::NullType, int i3 = 0, typename T4  = Loki::NullType, int i4 = 0,
    typename T5  = Loki::NullType, int i5 = 0, typename T6  = Loki::NullType, int i6 = 0,
    typename T7  = Loki::NullType, int i7 = 0, typename T8  = Loki::NullType, int i8 = 0,
    typename T9  = Loki::NullType, int i9 = 0, typename T10 = Loki::NullType, int i10 = 0
>
struct MakeTupleWithNamedMembers
{
private:
    typedef Loki::TL::MakeTypelist<pair<T1,i1>, pair<T2,i2>,
                                   pair<T3,i3>, pair<T4,i4>,
                                   pair<T5,i5>, pair<T6,i6>,
                                   pair<T7,i7>, pair<T8,i8>,
                                   pair<T9,i9>, pair<T10,i10>
                         >::Result type_list;
public:
    typedef Loki::GenScatterHierarchy<type_list, holder> Result;
};

//usage
class MyConstruct: public MakeTupleWithNamedMembers<int, foo, float, quux>::Result
{ };
like image 124
Alsk Avatar answered Dec 29 '22 22:12

Alsk