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
{ };