C++ – Downside of this macro construct and possible alternatives

c++class-designinterfacemacros

I recently saw some code using macros like

#define CONTAINS(Class, Name)\
    private:\
        std::list<Class> m_##Name##s;\
    public:\
        void add_##Name(const Class& a_##Name) {\
            m_##Name##s.push_back(a_##Name);\
        }\
        int get_##Name(int pos) {\
            return m_##Name##s.at(pos);\
        }\
        // ... more member functions

Later you can declare a class like

class my_class {
    CONTAINS(int, integer)
    // ...
};

and write

my_class a(...);
a.add_integer(10);

I was puzzled about this paste-in-macro-style because I'm missing concrete counter-arguments. But beside that I accept the following pros

  1. you can easily add a list interface for arbitrary types to your class
  2. you avoid frequently repeated code
  3. you have an easy to use interface (like add_integer(10))

Now I'm searching for alternatives which meet all these points above and avoid this old C macro style. My first idea was to create an abstract base class template

template<typename T>
class list_interface {
private:
    std::list<T> m_list;
public:
    void add_element(const T& x) {
        m_list.push_back(x);
    }
    // ... more member functions
};

and add it to my class via inheritance like this

class my_class : public list_interface<int> {
    // ...
};

Now I can write too

my_class a;
a.add_element(10);

but I'm concerned about the following points:

  1. you can only add one list to your class
  2. you publicly inherit from a class without virtual destructor
  3. I don't meet the third point of the pros (add_element(10) instead of add_integer(10))

My questions are:

  1. What are the drawbacks of the old C macro construct
  2. How can I provide a similar functionality without macros

Best Solution

How about:

#include <vector>

template<typename T>
class Plop
{
    std::vector<T>    data;
    public:
        void    add(T const& v) {data.push_back(v);}
        T       get(int pos)    {return data.at(pos);} // at() is not valid on lists.
};

class my_class
{
    public:
        Plop<int>       integer;
        Plop<float>     floater;
};

int main()
{
    my_class    x;
    x.integer.add(5);       // similar to x.add_integer(5);
    x.integer.get(0);       // similar to x.get_integer(0);
}

It meets all the requirements:

  1. you can easily add a list interface for arbitrary types to your class
  2. you avoid frequently repeated code
  3. you have an easy to use interface (like add_integer(10))

My questions are:

  1. What are the drawbacks of the old C macro construct

    • The ick factor.
    • Debugging.
    • Can pass individual list to other functions or methods.
  2. How can I provide a similar functionality without macros

    • See above.
Related Question