Генерация массива с использованием вариативных макросов

Я хочу сгенерировать массив указателей на функции, используя вариативный макрос. Вот пример.


Перед предварительной обработкой:

#define MY_MACRO(mClassName, ...) ???

struct test { 
    void a() { }
    void b() { }
    void c() { }
};

MY_MACRO(test, a, b, c);

После предварительной обработки:

struct test { 
    void a() { }
    void b() { }
    void c() { }
};

void(test::*)() getMemFnPtr(int mIdx) {
    static void(test::*)() fnPtrs[]{
        &test::a,
        &test::b,
        &test::c
    };
    return fnPtrs[mIdx];
}

Это возможно?

По сути, мне нужно иметь что-то до расширения массива, что-то после расширения массива и добавлять префикс к каждому расширенному аргументу макроса с переменным числом аргументов.


person Vittorio Romeo    schedule 04.01.2014    source источник
comment
Это возможно, если вы примете определенное ограничение на количество поддерживаемых аргументов. Но это также довольно сложно, см. этот вопрос/ответ для вдохновения :)   -  person Daniel Frey    schedule 04.01.2014
comment
Я думаю, что тип должен быть void(test::*fnPtrs[])(). Пожалуйста, пожалуйста используйте псевдоним.   -  person dyp    schedule 04.01.2014
comment
@DyP: я использую псевдоним в реальном коде :)   -  person Vittorio Romeo    schedule 05.01.2014
comment
@DanielFrey Можете ли вы опубликовать свой комментарий в качестве ответа? я хочу принять это   -  person Vittorio Romeo    schedule 05.01.2014
comment
Это было бы несправедливо, я почти ничего не делал, кроме как запоминал некоторые ключевые слова для поиска. Если вы хотите принять ответ, он должен быть от @DyP, использование Boost.Preprocessor далеко не тривиально, и я почти уверен, что он приложил к этому немало усилий.   -  person Daniel Frey    schedule 05.01.2014
comment
Хорошая точка зрения. Я приму его ответ.   -  person Vittorio Romeo    schedule 05.01.2014


Ответы (1)


Использование библиотеки препроцессора boost (хотя есть проблемы с clang++ и вариативными аргументами o.O, отлично работает с g++):

#include <boost/preprocessor/facilities/expand.hpp>
#include <boost/preprocessor/seq/transform.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>

#define CREATE_MFPTR(s, data, elem) \
    & BOOST_PP_EXPAND(data) :: BOOST_PP_EXPAND(elem)

#define CREATE_MFPTRS(class_name, ...)                                  \
    BOOST_PP_SEQ_ENUM(                                                  \
        BOOST_PP_SEQ_TRANSFORM(CREATE_MFPTR,                            \
                               class_name,                              \
                               BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))   \
    )                                                                   // end



struct test
{
    void a();
    void b();
    void c();
    void d();
};

using MFPtr = void (test::*)();
MFPtr arr[] = {
    CREATE_MFPTRS(test, a,b,c,d)
};

int main() {}

CREATE_MFPTRS(test, a,b,c,d) дает

& test :: a, & test :: b, & test :: c, & test :: d
person dyp    schedule 04.01.2014
comment
Конечно, вы также можете поместить определение массива в макрос и вызвать CREATE_MFPTR из этого макроса. - person dyp; 04.01.2014