Создание кода котельной пластины с помощью макросов - PullRequest
3 голосов
/ 08 мая 2011

У меня есть куча классов, таких как следующие,


class SomeClass : public Function{
public:

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

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

Я получил около 50 из них, и единственное, что отличается - это тело функции вызоваВозможно ли иметь макрос, который будет принимать имя и тело и заменять SomeClass именем и вставлять тело в функцию вызова?

Ответы [ 3 ]

4 голосов
/ 08 мая 2011

Конечно. Расширить тело функции-члена call немного проще, если у вас есть компилятор, который поддерживает переменные макросы. Хотя я использовал макрос stringize 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 в определении класса, а затем определить эту функцию отдельно.

2 голосов
/ 08 мая 2011

Чтобы избежать включения тела функции в вызов макроса, вы можете разбить определяющий класс макрос на префикс и суффикс:

#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";
};
0 голосов
/ 08 мая 2011

Вы использовали массовые getType() и toString() функции?Это не Java или C #, и, глядя на ваш код, я думаю, что вам нужно дополнительное обучение C ++ - еще один пример - вы вернули SomeClass из функции, которая возвращает void .

Однако то, что вы хотите, можно сделать с помощью довольно простого шаблона.

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 
...