1

すべての引数を別の (メンバー) 関数に転送する関数を自動生成するマクロを作成する必要があります。

JNI グルーが必要な理由を知る必要がある場合に備えて、JNI グルーの記述を簡素化する必要があります。このようにする必要がある他の理由は省略しますが、ブーストを使用できないことだけを述べます (ただし、必要な部分を切り取って、ブーストから自分のマクロに変換することはできます)。他のいくつかのライブラリ (jace など) もチェックしましたが、私のニーズに合ったものは見つかりませんでした。

要するに、JNI 関数の例を次に示します。

class TestClass
{
    void nativeTest(JNIEnv *, jobject, jint, jboolean)
    {
        ...
    }

    static TestClass* getPeer(JNIEnv *, jobject obj)
    {
        ...
    }
}

JNIEXPORT void JNICALL Java_com_noname_media_TestClass_nativeTest(
    JNIEnv *env, jobject obj, jint i, jboolean b
)
{
    TestClass* peer = TestClass::getPeer(env, obj, i, b);
    if(peer)
        return peer->nativeTest(env, obj, i, b);
    return;
}

JNI_FUNCTIONここで、 Java_com_noname_media_TestClass_nativeTest をすべて自動生成するマクロを書きたいと思います。少し考えた後、私は次のようにすることができると思います:

#define JNI_FUNCTION(functionName, functionReturn, functionArgs) \
JNIEXPORT functionReturn JNICALL                                 \
  Java_com_noname_media_TestClass##functionName(**WTF**)         \
{
        TestClass* peer = TestClass::getPeer(**WTF**);
        if(peer)
            return peer->functionName(**WTF**);
        return;
}

次に、を使用するJNI_FUNCTIONには、次のようなことができます。

JNI_FUNCTION(nativeTest, void, (JNIEnv *, jobject, jint, jboolean));

問題は、のリストの各エントリに自動番号付けされた引数名を追加する必要があるため、関数パラメーターを「クラック」する方法がわからないことですfunctionArgs

その他の落とし穴: 戻り値の型は何らかの型または void にすることができますが、void の場合は、JNI_VOID_FUNCTION通常の方法では簡単に実行できない場合に備えて、別の型にすることができます。私の場合、すべての jni 関数は常に のリストに少なくとも 2 つの引数を持ちます。functionArgsたとえば、空のリストにすることはできません()。複数の引数を含む単一の引数として functionArgs を使用する必要はありません。この方法でも問題ありません。

#define JNI_FUNCTION(functionName, functionReturn, ...)

うまくいくものは何でも...おそらく、ARG_1(...)など、ある位置でいくつかのマクロを抽出できるマクロが必要ですが、これまでのところ、その方法を頭の中ですべてラップすることはできません.

PS。ここSOで非常に良い説明があるc-preprocessorの使用法に関するいくつかの非常にクールな例を思い出しますが、今はそれらを見つけることができません。

編集: 基本的に、トリックは、自動番号付けされた名前を各引数に追加し、それらをそのままメンバー関数に渡すことです。このようにする必要があるのは、何よりも、プリプロセッサで他の自動生成を行っているためです。要するに、このマクロは実際には同様のマクロのグループ (ATL/WTL のようなもの) で使用されます。

JNI_TABLE_BEGIN(ClassName)
  JNI_FUNCTION(native1, void, (JNIEnv *, jobject, jint))
  JNI_FUNCTION(native2, void, (JNIEnv *, jobject, jint))
  JNI_FUNCTION(native3, jint, (JNIEnv *, jobject))
JNI_TABLE_END()
4

2 に答える 2

3

Boost.Preprocessor Sequencesを使用したソリューションは次のとおりです。

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/list/append.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/control/expr_if.hpp>
#include <boost/preprocessor/comparison/equal.hpp>
#include <boost/preprocessor/facilities/expand.hpp>

#define RET_TYPE_void 1)(1
#define IS_NOT_VOID(type) BOOST_PP_EQUAL(BOOST_PP_SEQ_SIZE((BOOST_PP_CAT(RET_TYPE_,type))),1)

#define JNI_PARAMS(r, data, i, elem) (elem p##i)
#define JNI_ARGS_PASS(r, data, i, elem) (p##i)

#define JNI_FUNCTION(functionName, functionReturn, PARAMS ) \
JNIEXPORT functionReturn JNICALL \
    Java_com_noname_media_TestClass##functionName(BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH_I(JNI_PARAMS,_,PARAMS)))  \
{ \
    TestClass* peer = TestClass::getPeer(BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH_I(JNI_ARGS_PASS,_,PARAMS))); \
    if(peer) \
        BOOST_PP_EXPR_IF(IS_NOT_VOID(functionReturn),return) peer->functionName(BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH_I(JNI_ARGS_PASS,_,PARAMS))); \
    BOOST_PP_EXPR_IF(IS_NOT_VOID(functionReturn),return functionReturn();) \
} \
/**/

JNI_FUNCTION(nativeTest, void, (jobject)(jint)(jboolean))

次のように展開します。

JNIEXPORT void JNICALL
Java_com_noname_media_TestClassnativeTest(jobject p0, jint p1, jboolean p2)
{
    TestClass* peer = TestClass::getPeer(p0, p1, p2);
    if(peer)
        peer->nativeTest(p0, p1, p2);
}

したがって、あなたの例は次のようになります。

#define JNI_TABLE_BEGIN(name) class name { public:
#define JNI_TABLE_END() };

JNI_TABLE_BEGIN(ClassName)
  JNI_FUNCTION(native1, void, (JNIEnv *)(jobject)(jint) )
  JNI_FUNCTION(native2, void, (JNIEnv *)(jobject)(jint) )
  JNI_FUNCTION(native3, jint, (JNIEnv *)(jobject) )
JNI_TABLE_END()

そして、次のように展開されます。

class ClassName
{
public:
    JNIEXPORT void JNICALL
    Java_com_noname_media_TestClassnative1(JNIEnv * p0, jobject p1, jint p2)
    {
        TestClass* peer = TestClass::getPeer(p0, p1, p2);
        if(peer)
            peer->native1(p0, p1, p2);
    }
    JNIEXPORT void JNICALL
    Java_com_noname_media_TestClassnative2(JNIEnv * p0, jobject p1, jint p2)
    {
        TestClass* peer = TestClass::getPeer(p0, p1, p2);
        if(peer)
            peer->native2(p0, p1, p2);
    }
    JNIEXPORT jint JNICALL
    Java_com_noname_media_TestClassnative3(JNIEnv * p0, jobject p1)
    {
        TestClass* peer = TestClass::getPeer(p0, p1);
        if(peer)
            return peer->native3(p0, p1);
        return jint();
    }
};
于 2012-10-26T22:09:59.430 に答える
0

これまでのところ、解決策として適切なアイデアが 1 つあります。SOの回答を見ると、引数の数を数える方法の例が見つかりました。このマクロを使用すると、引数の数を連結してfunctionArgs、定義済みのマクロを呼び出すことができます。JNI_FUNCTION_5これは、引数のリストで 5 つの引数を取ります。必要なのは、 VA_ARGSのリストからいくつかの引数を抽出できることだけです。__VA_ARG_N(num) のようなマクロ。

からいくつかの引数を抽出する方法は次の__VA_ARGS__とおりです。

#define ARG_REST(arg, ...) __VA_ARGS__
#define ARG0(arg0, ...) arg0
#define ARG1(...) ARG0(ARG_REST(__VA_ARGS__))
#define ARG2(...) ARG1(ARG_REST(__VA_ARGS__))
... etc.

次に、リストの引数と型のペア、または引数のみを生成する特別なマクロを作成しました。

だから、最終的に、私はこれを行うことができました:

JNI_FUNCTION(void, nativeSetOrientation, (JNIEnv *, jobject, jint, jboolean));
JNI_FUNCTION(void, nativeStartRecording, (JNIEnv *, jobject, jstring, jint));

修正した方がよい唯一の問題はreturnType、次のような void の特別な処理を追加することです。

    if(peer)
        IS_NOT_VOID(returnType, return) peer->functionName(**WTF**);
    IS_NOT_VOID(returnType, return returnType();)

IS_NOT_VOID には次のアクションが必要です。

#define IS_NOT_VOID(type, expr) if(type == void) expr

あれは

IS_NOT_VOID(void, return void();) -> expands to nothing
IS_NOT_VOID(int, return int();) -> expands to return int();

適切に行う方法はありますか?ただし、考えられるすべての型を反復処理し、JNI 関数に渡すことができるすべての型に対して 30 の定義を作成するという明白な解決策は除きます。このようなもの:

#define _IF_NOT_VOID(type, expr) _IF_NOT_VOID##type(expr)
#define _IF_NOT_VOIDvoid(expr) //void type...
#define _IF_NOT_VOIDjboolean(expr) expr
#define _IF_NOT_VOIDjbyte(expr) expr
#define _IF_NOT_VOIDjchar(expr) expr
于 2012-10-26T22:01:19.497 に答える