peper0
peper0

Reputation: 3223

Object and it's class definition in one macrodefinition call

I'd like to write a macro that in the following usage defines a global object foobar of a class defined below it.

SOMEMACRO(foobar)
{
public:
   int a;
};

In other words, I'd like the above to have the same effect as:

class SomeClassPossiblyWith_foobar_InItsName
{
public:
   int a;
};
SomeClassPossiblyWith_foobar_InItsName foobar;

It's very important to giving exactly the "foobar" name to the object (or at least call in such a way a reference to the proper object). The name of class doesn't matter as long as it allow to use the macro several times.

It's rather hard, since class should be usually defined before it is used, but maybe there exist some tricky (possibly templates-involved) way of achieving it?

Upvotes: 3

Views: 230

Answers (4)

Leonardo Raele
Leonardo Raele

Reputation: 2823

EDIT: Added more explanation to the codes.

A solution with templates would be as follows:

I have created a template for classes that should have an instance with global access when created. I think this is what you want. (I have named it as Singleton reffering to the design pattern with the name) .h:

// C++ header for template Singleton
template<typename T>
class Singleton : public T {
    static Singleton<T>* instance;
    Singleton();
public:
    static Singleton<T>* getInstance();
};

getInstance() method will be from where you will get that instance. It can be an object instead of a pointer, but I like it better this way because it's more versatile with you want to do something more complex like changing the instance at runtime; also it allows to instantiate the object only when it is used, preventing no need memory alloc. .cpp:

// C++ source for template Singleton
template<typename T>
Singleton<T>* Singleton<T>::instance = NULL;

template<typename T>
Singleton<T>::Singleton()
: T()
{}

template<typename T>
Singleton<T>* Singleton<T>::getInstance()
{
    if (instance == NULL)
    {
        instance = new Singleton<T>();
    }
    return instance;
}

You can implement any class you want normally and use Singleton template to ensure that you will always dealing with the same global instance of some class. You can also use a typedef to caliry type names, if you want. Your class definition:

// Definition of class foobar
class foobar_impl {
public:
    int a;
};

typedef Singleton<foobar_impl> Foobar;

Then, you use the template to retreave the instance of foobar_impl:

int main(int argc, char** argv)
{
    Foobar *pf = Foobar::getInstance();
    return 0;
}

The problem of this solution, however, is that Singleton template will work only with classes that have an empty constructor. But so does your examples, so I think this is what you want.

Upvotes: 0

Leonardo Raele
Leonardo Raele

Reputation: 2823

You can do this way:

#define SING(classname, body) class SING_##classname \
body \
; SING_##classname classname;

Then, use it this way:

SING (foobar, {
    public:
        int a;
    }
);

Upvotes: 1

peper0
peper0

Reputation: 3223

I a meantime I've found solution that make reference and initialize it with proper object, which somehow answer the question. I'm not sure it is standard complaint (it complies with gcc 4.6).

template<typename T>
T &delayed_make_object()
{
    static T obj;
    return obj;
}

#define DOIT(_name) \
    class TypeFor ## _name; \
    TypeFor ## _name & _name = delayed_make_object<TypeFor ## _name>(); \
    class TypeFor ## _name


DOIT(foo)
{
    public:
    int abc;
};  

DOIT(bar)
{
    public:
    int cba;
};

int main()
{
  foo.abc=bar.cba;   // works!
}

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409482

It very simple, using the preprocessor concatenation operator ##.

Something like:

#define SOMEMACRO(name) \
SomeClassPossiblyWith_##name##_InItsName name; \
class SomeClassPossiblyWith_##name##_InItsName

Upvotes: 1

Related Questions