我需要编写一个宏来自动生成一个将所有参数转发给另一个(成员)函数的函数。
如果您需要知道我为什么需要它,我需要简化 JNI 胶水的编写。 我将省略我需要以这种方式完成的其他原因,我只是提到我不能使用 boost(尽管我可能会撕掉需要的部分并将 boost 转换为我自己的宏);我还检查了其他一些库(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 函数在 functionArgs
列表中总是至少有两个 args,例如它不能是空列表 ()
。
我不必将 functionArgs 用作包含多个参数的单个参数,我也接受这种方式:
#define JNI_FUNCTION(functionName, functionReturn, ...)
无论什么工作...也许我需要某种宏,允许我在某个位置提取一些宏,比如 ARG_1(...) 等,但到目前为止我无法将它全部包装在我的大脑中如何去做。
附言。我记得一些关于 c-preprocessor 用法的非常酷的例子,在 SO 中有很好的解释,但现在找不到它们,如果你有它的书签,也许我需要的只是研究它们。
编辑: 基本上,诀窍是为每个参数添加自动编号的名称,然后按原样将它们传递给成员函数。我需要以这种方式完成的原因是因为除此之外,我还使用预处理器完成了一些其他自动生成。简而言之,这个宏实际上会被用在一组类似的宏中(类似于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()
最佳答案
这是使用 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();
}
};
关于c++ - 使用 c-preprocessor 自动生成函数转发器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13094383/