使用宏创建样板代码

Creating Boiler Plate Code using Macros

本文关键字:代码 创建      更新时间:2023-10-16

我有一堆类,如下所示,


class SomeClass : public Function{
public:
   ref call(ref args){
    // do & return stuff
   }
   int getType(){return TYPE;}
   ref toString(){ return "SomeClass";}
};

我得到了其中的 50 个,唯一不同的是调用函数的主体。是否可以有一个宏,它将采用名称和主体,并将"SomeClass"替换为名称并将主体插入调用函数?

当然。 如果您有一个支持可变参数宏的编译器,则扩展 call 成员函数的主体会更容易一些。 虽然我使用了 Boost.Preprocessor 的字符串宏,但编写自己的宏是微不足道的。

#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__

用作:

DEFINE_CLASS(SomeClass, (return ref()))

call正文需要用括号括起来,以便正文中存在的任何逗号都不会被视为宏参数分隔符。 或者,您可以在类定义中声明call函数,然后单独定义该函数。

为了避免在

宏调用中包装函数的主体,可以将类定义宏拆分为前缀和后缀:

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

调用方式:

DEFINE_FUNCTION_CLASS_BEGIN(SomeClass)
// Stuff.
DEFINE_FUNCTION_CLASS_END

或者,使用模板:

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

并专门化它:

template<>
ref SomeClass<TYPE>::call(ref args) {
    // Stuff.
};
template<>
std::string SomeClass<FOO>::toString() {
    return "FOO";
};

你用过大量getType()toString()函数吗?这不是Java或C#,看看你的代码,我认为你需要一些额外的C++学费 - 另一个例子是你从一个返回void的函数返回了"SomeClass"。

但是,您想要的可以使用非常简单的模板来完成。

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