Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用c预处理器自动生成函数转发器_C++_C_C Preprocessor - Fatal编程技术网

C++ 使用c预处理器自动生成函数转发器

C++ 使用c预处理器自动生成函数转发器,c++,c,c-preprocessor,C++,C,C Preprocessor,我需要编写一个宏,自动生成一个函数,将所有参数转发给另一个(成员)函数 我需要在简化编写JNI胶水的情况下,如果你需要知道我为什么需要它。 我将省略我需要这样做的其他原因,我只是提到我不能使用boost(尽管,我可能会删除需要的部分并将boost转换为我自己的宏);我还检查了其他一些LIB(jace等),但没有找到任何适合我需要的 简而言之,以下是JNI函数的示例: class TestClass { void nativeTest(JNIEnv *, jobject, jint, jb

我需要编写一个宏,自动生成一个函数,将所有参数转发给另一个(成员)函数

我需要在简化编写JNI胶水的情况下,如果你需要知道我为什么需要它。 我将省略我需要这样做的其他原因,我只是提到我不能使用boost(尽管,我可能会删除需要的部分并将boost转换为我自己的宏);我还检查了其他一些LIB(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\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