C++ 使用c预处理器自动生成函数转发器
我需要编写一个宏,自动生成一个函数,将所有参数转发给另一个(成员)函数 我需要在简化编写JNI胶水的情况下,如果你需要知道我为什么需要它。 我将省略我需要这样做的其他原因,我只是提到我不能使用boost(尽管,我可能会删除需要的部分并将boost转换为我自己的宏);我还检查了其他一些LIB(jace等),但没有找到任何适合我需要的 简而言之,以下是JNI函数的示例:C++ 使用c预处理器自动生成函数转发器,c++,c,c-preprocessor,C++,C,C Preprocessor,我需要编写一个宏,自动生成一个函数,将所有参数转发给另一个(成员)函数 我需要在简化编写JNI胶水的情况下,如果你需要知道我为什么需要它。 我将省略我需要这样做的其他原因,我只是提到我不能使用boost(尽管,我可能会删除需要的部分并将boost转换为我自己的宏);我还检查了其他一些LIB(jace等),但没有找到任何适合我需要的 简而言之,以下是JNI函数的示例: class TestClass { void nativeTest(JNIEnv *, jobject, jint, jb
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\u函数
宏来自动生成所有Java\u com\u noname\u media\u TestClass\u 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(nativeTest, void, (JNIEnv *, jobject, jint, jboolean));
if(peer)
IS_NOT_VOID(returnType, return) peer->functionName(**WTF**);
IS_NOT_VOID(returnType, return returnType();)
#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
然后,要使用JNI_函数
,我可以这样做:
#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(nativeTest, void, (JNIEnv *, jobject, jint, jboolean));
if(peer)
IS_NOT_VOID(returnType, return) peer->functionName(**WTF**);
IS_NOT_VOID(returnType, return returnType();)
#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
问题是我不知道如何“破解”函数参数,因为我需要为functorgs
列表中的每个条目添加自动编号的参数名
其他问题:返回类型可以是某个类型或void,但对于void情况,我可能有单独的JNI\u void\u函数
,以防无法使用常规方法轻松完成。在我的例子中,所有jni函数在函数rgs
列表中始终至少有两个参数,例如,它不能是空列表()
。
我不必将functionArgs用作包含多个参数的单个参数,我也同意这种方式:
#define JNI_FUNCTION(functionName, functionReturn, ...)
无论什么有效。。。也许我需要某种宏,可以让我在某个位置提取一些宏,比如ARG_1(…)等等,但到目前为止,我还不能在我的脑子里把这些宏都包起来怎么做
顺便说一句,我记得一些关于c预处理器使用的超级酷的例子,在这里有很好的解释,但是现在找不到,如果你把它书签了,也许我只需要看看它们
编辑:
基本上,诀窍是将自动编号的名称添加到每个参数,然后按原样传递给成员函数。我之所以需要这样做,是因为除此之外,我还使用预处理器完成了一些其他自动生成。简而言之,该宏实际上将用于一组类似的宏(类似于ATL/WTL):
到目前为止,我有一个想法可能适合作为解决方案。我看了这么多答案。 使用这个宏,我可以连接
functorgs
中的参数计数,并调用一些预定义的宏,例如JNI\u FUNCTION\u 5
,它在参数列表中包含5个参数。我所需要的只是能够从VA_ARGS列表中提取一些参数。一些宏,如uu VA_ARG_N(num)
这里有一种从\uu VA\u ARGS\uu
中提取一些参数的方法:
#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));
唯一需要解决的问题是为void添加特殊处理returnType
,如下所示:
#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(nativeTest, void, (JNIEnv *, jobject, jint, jboolean));
if(peer)
IS_NOT_VOID(returnType, return) peer->functionName(**WTF**);
IS_NOT_VOID(returnType, return returnType();)
#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
如果为非无效,则应执行以下操作:
#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 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(nativeTest, void, (JNIEnv *, jobject, jint, jboolean));
if(peer)
IS_NOT_VOID(returnType, return) peer->functionName(**WTF**);
IS_NOT_VOID(returnType, return returnType();)
#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
以下是使用Boost.Preprocessor的解决方案: 因此,您的示例将变成:
#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()
并扩展至:
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);
}
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吗?是java还是C++的JNI函数?哦,好的,乔纳森,你是那个有最酷的C预处理器样本的人,我马上就知道你的名字了。)我会检查你的回复,也许我会在那里找到我需要的。是的,我的帖子中只有c/c++的东西,这里没有涉及java;它只能是C++。所以,你应该把你的问题标记为C++。另一个标签可以。在决定可以做什么和不能做什么之前,你应该先查看Boost预处理器代码。你不能用预处理器生成转发函数。@n.m.我很确定你错了。。。它不会非常好看,但可以做一些很好的事情。这是一个非常好的结果。但看起来我在没有使用boost的情况下,做得更好了。请检查我自己的答复和解释。唯一需要解决的问题是回归;当它实际上必须返回jint()时,它是不好的;但是,处理void返回类型也有一个问题。使用variadics宏,这不是C++98/C++03的标准,而Boost.Preprocessor序列是可移植的。此外,我还为void返回类型添加了预处理器条件。简而言之,这个想法是使void case扩展为(1,1,0),但其他case扩展为(something,0)。然后我们可以使用变量宏,它扩展到它的第二个参数。。。等等我相信,对于其他编译器也可以这样做。顺便问一下,你在那个项目中使用了哪些编译器?一般来说,预处理器技巧是不可移植的-一些编译器有一个bug,一些-其他,这就是我喜欢使用Boost的原因。预处理器-它有很多ifdef,使这些东西可移植。这是gcc-4.3.4的版本-你可以在底部看到Ideone输出。使用Boost的可移植版本。适用于MSVC和GCC