Возможно ли использовать макросы для обработки содержимого? - PullRequest
0 голосов
/ 14 октября 2011

В настоящее время я работаю с JNI (Java Native Interface) для отправки данных между Java и C ++. После реализации небольшого количества кода я понял, что код для каждого метода всегда был похожим. Примером может быть:

JNIEXPORT void JNICALL Java_com_trial_jni_Receiver_setData__II(JNIEnv * env, jobject thiz, jint nativeObject, jint value)  
{  
    reinterpret_cast<Receiver *>(nativeObject)->setData(value);  
}  

JNIEXPORT void JNICALL Java_com_trial_jni_Receiver_setData__ILjava_lang_String_2(JNIEnv *env, jobject thiz, jint nativeObject, jstring value)  
{  
    reinterpret_cast<Receiver *>(nativeObject)->setData(value);  
}

Поскольку весь код имеет схожую структуру, я решил сгенерировать набор макросов для автоматической генерации всего этого кода. Благодаря ответу Грегори Пакоша в этой ссылке Возможно ли перебирать аргументы в вариационных макросах? Теперь я могу с помощью препроцессора проверить, сколько параметров я ввел в макрос, и обработать каждый отдельный параметр.

Но из предыдущего примера есть то, чего я не могу достичь, чего бы я хотел. Предположим, у меня есть этот метод внутри макроса с именем JNI_METHOD. Я хотел бы сделать что-то вроде этого:

#define JNI_METHOD(package,clazz,method,...) \  
    JNIEXPORT void JNICALL Java_ ##package## _ ##clazz## _ ##method##__II(JNIEnv * env, jobject thiz, jint nativeObject, SET_DECLARATION_PARAMS(__VA_ARGS__ )) \  
    { \  
        reinterpret_cast<clazz *>(nativeObject)->method(SET_DECLARED_PARAMS(__VA_ARGS__)); \  
    }  

JNI_METHOD(com_trial_jni,Receiver,setData,jint);  
JNI_METHOD(com_trial_jni,Receiver,setData,jstring);  

Чтобы не задавать этот вопрос слишком долго, я не вставлял объявление SET_DECLARATION_PARAMS и SET_DECLARED_PARAMS, но первое приведёт к чему-то вроде 'jint arg1', а второе в 'arg1' без типа.

Вопрос в том, есть ли способ сгенерировать макрос, возвращающий «I» для «jint» или «Ljava_lang_String_2» для «jstring». Обратите внимание, что строковая спецификация не может использоваться, и это необходимо, чтобы во втором сгенерированном имени метода было указано «ILjava_lang_String_2» вместо «II».

Спасибо!

Ответы [ 2 ]

2 голосов
/ 14 октября 2011

Ну, ссылка, которую вы предоставили, в значительной степени дает вам необходимое решение.Учтите это:

#define CONCATENATE(arg1, arg2)   CONCATENATE1(arg1, arg2)
#define CONCATENATE1(arg1, arg2)  CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2)  arg1##arg2

#define JNI_TRANSLATE_TYPE_jint I
#define JNI_TRANSLATE_TYPE_jstring Ljava_lang_String_2

#define JNI_TRANSLATE_TYPE(T) CONCATENATE(JNI_TRANSLATE_TYPE_, T)

Тест, на VS2010:

#define STRINGIZE(arg)  STRINGIZE1(arg)
#define STRINGIZE1(arg) STRINGIZE2(arg)
#define STRINGIZE2(arg) #arg

#pragma message("jint: " STRINGIZE(JNI_TRANSLATE_TYPE(jint)))
#pragma message("jstring: " STRINGIZE(JNI_TRANSLATE_TYPE(jstring)))

Выход:

1>  jint: I
1>  jstring: Ljava_lang_String_2
0 голосов
/ 14 октября 2011

Вы также можете использовать SWIG для создания упаковщиков JNI для вас. Он может обрабатывать и скрывать весь неприятный код для обертывания объектов с помощью JNI, а также многие другие языковые отображения.

...