如何使用 C++ 模板实现从类型到对象方法调用的映射?

Posted

技术标签:

【中文标题】如何使用 C++ 模板实现从类型到对象方法调用的映射?【英文标题】:How to implement mapping from type to object method call using C++ templates? 【发布时间】:2018-08-08 14:24:55 【问题描述】:

我想使用 C++ 模板为 JNI 代码中的 java 数组开发(又一个)包装器。主要目标是提高我的 C++ 模板编程技能。

我使用 android NDK 编译代码(编译器是 Clang 6.0.2)

到目前为止我已经做到了:

#include <jni.h>

template <typename T>
struct TypeToObjectType;

template <>
struct TypeToObjectType<jbyteArray>

    typedef jbyte type;
;

template <>
struct TypeToObjectType<jintArray>

    typedef jint type;
;

template <typename javaArrayT, typename nativeT>
class Java_array
    JNIEnv *env;
    jboolean is_copy;
    jsize array_len;

    javaArrayT array;
    typename TypeToObjectType<javaArrayT>::type *array_elements;

public:
    Java_array(JNIEnv *_env, javaArrayT _array)
        : env(_env)
        , array(_array)
        , array_len(-1)
    
        array_elements = env->GetByteArrayElements(array, &is_copy);  //TODO: make it resolving automatically to other primitives
    

    ~Java_array() 
        env->ReleaseByteArrayElements(array, array_elements, JNI_ABORT);
    

    jsize len()
        if (array_len < 0)
           array_len = env->GetArrayLength(array);
        return array_len;
    

    operator nativeT* () const 
        return reinterpret_cast<nativeT*>(array_elements);
    ;
;

这不适用于int[]float[] 和除byte[] 之外的其他数组,因为此类调用GetByteArrayElements

我使用struct TypeToObjectType建立映射jbyteArray -> jbyte, jintArray -> jint

此映射缺少部分 java 类型 -> JEnv 方法调用,即 jbyteArray -> (GetByteArrayElements, ReleaseByteArrayElements), jintArray -> (GetIntArrayElements, ReleaseIntArrayElements)`

我该怎么做?

如何使用 C++11、C++14 的功能改进我的代码?

【问题讨论】:

【参考方案1】:

您可以将指向成员的指针添加到您的 trait。

template <>
struct TypeToObjectType<jbyteArray>

    typedef jbyte type;
    static constexpr jbyte * (JNIEnv::* const GetElements)(jbyteArray, jboolean *) = &JNIEnv::GetByteArrayElements;
    static constexpr void (JNIEnv::* const ReleaseElements)(jbyteArray, jbyte *, decltype(JNI_ABORT)) = &JNIEnv::ReleaseByteArrayElements;
;

template <>
struct TypeToObjectType<jintArray>

    typedef jint type;
    static constexpr jint * (JNIEnv::* const GetElements)(jintArray, jboolean *) = &JNIEnv::GetIntArrayElements;
    static constexpr void (JNIEnv::* const ReleaseElements)(jintArray, jint *, decltype(JNI_ABORT)) = &JNIEnv::ReleaseIntArrayElements;
;

你通过稍微不同的语法调用它

Java_array(JNIEnv *_env, javaArrayT _array)
    : env(_env)
    , array(_array)
    , array_len(-1)

    array_elements = (env->*TypeToObjectType<javaArrayT>::GetElements)(array, &is_copy);


~Java_array() 
    (env->*TypeToObjectType<javaArrayT>::ReleaseElements)(array, array_elements, JNI_ABORT);

【讨论】:

啊,对不起,我搞砸了如何声明指针 const,而不是函数返回类型。语法相当晦涩

以上是关于如何使用 C++ 模板实现从类型到对象方法调用的映射?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 FreeMarker 模板调用对象的 java 方法?

干货C++通过模板特化实现类型萃取实例--实现区分基本类型与自定义类型的memcpy

C++从青铜到王者第六篇:C++模板初阶

C++ 在不知道子类型的情况下从父类型调用子方法

从一个模板化容器投射到另一个

实验2:函数重载函数模板简单类的定义和实现