开发者

Creating Boiler Plate Code using Macros

开发者 https://www.devze.com 2023-03-03 11:10 出处:网络
I have a bunch of classes such as 开发者_StackOverflow社区the following, class SomeClass : public Function{

I have a bunch of classes such as 开发者_StackOverflow社区the following,


class SomeClass : public Function{
public:

   ref call(ref args){
    // do & return stuff
   }

   int getType(){return TYPE;}
   ref toString(){ return "SomeClass";}
};

I got like 50 of these and the only thing that is different is the body of the call function. Is it possible to have a macro that will take a name and a body and replace "SomeClass" with name and insert body into call function?


Sure. Expanding the body of the call member function is a bit easier if you have a compiler that supports variadic macros. While I've used Boost.Preprocessor's stringize macro, it is trivial to write your own.

#define DEFINE_CLASS(name, parenthesized_call_body)                 \
    class name : public Function {                                  \
        ref call (ref args) {                                       \
            DEFINE_CLASS_CALL_BODY parenthesized_call_body          \
        }                                                           \
        int getType() { return TYPE; }                              \
        const char* toString() { return BOOST_PP_STRINGIZE(name); } \
    };

#define DEFINE_CLASS_CALL_BODY(...) __VA_ARGS__

Used as:

DEFINE_CLASS(SomeClass, (return ref()))

The call body needs to be parenthesized so that any commas present in the body are not treated as macro argument separators. Alternatively, you could just declare the call function in the class definition and then define that function separately.


To avoid wrapping the body of the function in a macro invocation, you can split the class-defining macro into prefix and suffix:

#define DEFINE_FUNCTION_CLASS_BEGIN(name) \
    class name : public Function { \
    public: \
        ref call(ref args) {

#define DEFINE_FUNCTION_CLASS_END \
        } \
        int getType() { return TYPE; } \
        void toString() { return #name; } \
    };

Invoke with:

DEFINE_FUNCTION_CLASS_BEGIN(SomeClass)

// Stuff.

DEFINE_FUNCTION_CLASS_END

Alternatively, use a template:

template<int Type>
class SomeClass : public Function {
public:
    int getType() { return Type; }
    ref call(ref args) {}
    std::string toString() {}
};

And specialise it:

template<>
ref SomeClass<TYPE>::call(ref args) {
    // Stuff.
};

template<>
std::string SomeClass<FOO>::toString() {
    return "FOO";
};


You've used a mass getType() and toString() functions? This isn't Java or C#, and looking at your code, I think that you need some additional C++ tuition- another example is that you returned "SomeClass" from a function that returns void.

However, what you want can be done with a pretty simple template.

template<typename T> class SomeClass : public Function {
    T t;
public:
    SomeClass(const T& ref)
        : t(ref) {}
    ret call(args) {
        return t(args);
    }
    int getType() { return TYPE; }
    std::string toString() { return "someClass"; } 
};

ret func(argtypes) { ... }
SomeClass<ret(*)(argtypes)> instance(func);
struct lols {
    // .. Whatever you want in here
    ret operator()(args) { ... };
}
SomeClass<lols> anotherinstance(lols()); // or constructor arguments if needed 
0

精彩评论

暂无评论...
验证码 换一张
取 消