views:

256

answers:

9

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 ?

A: 

Templates can't specify variable names. If you're deciding at compilation time what to have in the class, you should be able to specify it directly in source code.

You may be able to accomplish what you want with some macros, but I dare not venture into that dark territory.

JoshD
+2  A: 

You can't specify names using templates, only types or certain kinds of values. You may be able to do it using macros, however trying to do too much within the language is a trap I have fallen into too many times .. there is another path that may work for you : code generation

Consider writing a script to read in some config and spit out the definitions of your classes. Add the script to your build process. This may be easier to maintain and understand than the black arts of template metaprogramming or macro skulduggery.

python is what I'd use for the script, with per class configuration in something easy to parse like json - but those are side issues

In my current project we have thousands of lines of generated files, spread across over 100 files... and those generation scripts are modified relatively regularly, and painlessly.

Michael Anderson
+1  A: 

I remember that Andrei Alexandrescu describes something similar in his book "Modern C++". I do not have a copy here so I can't tell exactly what and where it was.

As others have pointed out, it is not possible to have names as template arguments, but he created a struct which could be accessed like data.get<T1>() or something like that. If there were more than one data of one type you could do data.get<T1,2>().

Maybe that helps.

Philipp
A: 

You can do something similar, but they won't have distinct names:

template <class T, int num_t >
MyClass
{
     T var[num_T];
};

This overlooks bounds checking, but that's another story.

TokenMacGuy
@TokenMacGuy Thats Ok but types can be different and accessing via distinct name is must for me :)
Pardeep
+3  A: 

Not possible as described. You might get equivalent functionality using boost's preprocessor library.

Ultimately what you're asking for differs from simply passing say...

struct Members
{
    int a_;
    double b_;
};

...into...

template <class Members>
class Add_Stuff : public Members
{
  public:
    doSomething() { ... };
};

...in that doSomething is given the ability to iterate over and print the members, right?

You can also write a simple program/script that reads a list of types and identifiers and outputs the C++ code you require. If you have a lot of fields to deal with, this is probably a good approach. As a minimal off-the-top-of-my-head outline, and assuming input like so the newlines enforce a simple type vs identifier division (making you create typedefs for arrays etc):

std::string
idn1
const int*
idn2
my_typedef
ind3

...you can generate some C++ code ala...

std::ostringstream streaming;
streaming << "    void somefunc() const\n{\n    std::cout ";

cout << "class " << class_name << "\n{\n";
while (cin.getline(type) && cin.getline(identifier))
{
    cout << "    " << type << ' ' << identifier << '\n';
    streaming << "<< \"" << identifier << " \" << identifier << "\n        ";
}
cout << "  public:\n" << streaming.str() << "\n"
        "};\n";

Obviously you could clean up the input to allow a more natural C++ expression of types and identifiers and complicate the parsing logic - a regexp may be good enough for your needs, or you could try spirit or do it yourself.

Preprocessor hackery can achieve something similar directly inside C++, but IMHO it will be even uglier and more time consuming to write and maintain.

If you don't actually need to access the members by identifier, you might do what TokenMacGuy suggests if every field can have the same type (not so bad - consider boost::variant or ~::any), or there's another option if you can ensure every field has a distinct type (again, this can be forced via trivial wrapper template classes): what I call a "type map" - where you can use the type as a key into what's effectively an associative container of type-distinct values, with all lookup resolved at compile time and support for the automatic iteration needed for your somefunc() implementation. Could combine that with strings for run-time type naming if desired, but can't achieve identifier strings that are resolved or validated at compile time.

I implemented such maybe 6 years ago (atop Alexandrescu's Loki library using type lists) and asked on the boost mailing list whether anyone was interested, but nobody saw the utility of it and I didn't really try to explain. It's actually very useful for logging systems, which prompted me to write it in the first place. Anyway, I suspect I didn't bother to post code to the vault for that one, and don't have it handy, so you'd need to start from scratch unless MPL or some other library has implemented their own similar "container" meanwhile (or beforehand...?).

Tony
@Tony Yes you are right. I had also thought of similar line on deriving from a structure and generating that structure with different member variable names was not clicking. These types can be different and accessing variable by name is the most required part of my implementation.
Pardeep
@Pardeep: I see. You might want to check out the boost serialisation library then - I think it has preprocessor macros to capture some extra meta-data about members, which you can presumably use to iterate over them when implementing your own functions ala doSomething()....
Tony
A: 

Loki's typelist. link text Quite complicated for me. But I think what you want can be done using this.

Manoj R
A: 

Have a look at std::tuple.

This allows an arbitrary (but fixed at compile-time) number of data elements, and type-safe access per index.

sbi
+2  A: 

I find the question underspecified, it's not clear what the purpose is.

For serialization I'd consider the Boost library's serialization support.

For named, strictly typed optional arguments one possibility is to use the Boost parameters library, and a second, simpler-to-use possibility is my own options pack support. It's essentially a set of macros that, via some impenetrable internal template black magic, generates classes like you ask for. I wrote an article in Dr. Dobbs Journal about it, but here's a usage example illustrating a main advantage, that the generated option classes can be extended in parallel with another class hierarchy:

#include <iostream>
#include <progrock/cppx/arguments/options_boosted.h>

struct AbstractButton
{
    // These members are not part of the cppx options scheme: in actual
    // usage you will instead have e.g. some API level widget states.
    int     hTextAlign;
    int     vTextAlign;
    int     buttonPlacement;

    // Defines a local class 'Options' with specified options & defaults.
    CPPX_DEFINE_OPTIONCLASS( Options, CPPX_OPTIONS_NO_BASE,
        ( hTextAlign,       int,        0   )
        ( vTextAlign,       int,        0   )
        ( buttonPlacement,  int,        0   )
        )

    explicit AbstractButton( Options const& params = Options() )
        : hTextAlign( params.hTextAlign() )
        , vTextAlign( params.vTextAlign() )
        , buttonPlacement( params.buttonPlacement() )
    {}
};

struct CheckBox: AbstractButton
{
    bool    isAuto;
    bool    is3State;

    // Defines an extension of the base class' 'Options' class.
    CPPX_DEFINE_OPTIONCLASS( Options, AbstractButton::Options,
        ( isAuto ,          bool,       true    )
        ( is3State,         bool,       false   )
        )

    explicit CheckBox( Options const& params = Options() )
        : AbstractButton( params )
        , isAuto( params.isAuto() )
        , is3State( params.is3State() )
    {}
};

void show( CheckBox const& cb )
{
    std::cout
        << std::boolalpha
        << "hTextAlign = " << cb.hTextAlign
        << ", isAuto = " << cb.isAuto << ".\n";
}

int main()
{
    typedef CheckBox::Options   CBOptions;

    CheckBox        widget1;
    show( widget1 );                // 0, true (the default values)

    CheckBox        widget2( CBOptions().hTextAlign( 1 ) );
    show( widget2 );                // 1, true

    CheckBox        widget3( CBOptions().hTextAlign( 1 ).isAuto( false ) );
    show( widget3 );                // 1, false
}

The above code uses some undocumented Boost magic to provide C++98 variadic macros. :-)

There's also a more basic un-Boosted set of macros which removes the Boost dependency, at the cost of having to specify the number of members in each generated class.

Cheers & hth.,

– Alf

Alf P. Steinbach
+1  A: 

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
{ };
Alsk
@Pardeep: solution improved: no need in underscore prefix. now, I like how it looks)
Alsk
omg... we can easily inject user-specified names for methods and variables into libraries' and frameworks' code, not only types. Voila composition of abstract structures with domain specifics like BinaryTree<FarthestNode, NearestNode> (usage will be pretty self-documenting).
Alsk