用例证学习 c++范型编程(模板元)

用例子学习 c++范型编程(模板元)

此文版权属于作者用例证学习 c++范型编程(模板元)所有,任何人、媒体或者网站转载、借用都必须征得作者本人同意!

例子用一个实例:通过 jni 接口读取 java 对象。

#include <jni.h>

//=============================================================
// 场景 1,最常见
namespace t1 {

    //=============================================================

#if 0
    // java 类
    public class Frame {
        public int width = 0;
        public int height = 0;
    }
#endif

    class Frame1 {
    public:
        jint width;
        jint height;
    };

    //-------------------------

    void getFrame(JNIEnv* env, jobject jframe, Frame1& frame) {
        jclass cls = env->GetObjectClass(jframe);
        {
            jfieldID field = env->GetFieldID(cls, "width", "I");
            frame.width = env->functions->GetIntField(env, jframe, field);
        }
        {
            jfieldID field = env->GetFieldID(cls, "height", "I");
            frame.height = env->functions->GetIntField(env, jframe, field);
        }
    }

    //=============================================================
    // 修改 Frame 的数据成员 height 的类型,对应的代码修改如下

#if 0
    // java 类
    public class Frame {
        public int width = 0;
        public long height = 0;
    }
#endif

    class Frame2 {
    public:
        jint width;
        jlong height;
    };

    //-------------------------

    void getFrame(JNIEnv* env, jobject jframe, Frame2& frame) {
        jclass cls = env->GetObjectClass(jframe);
        {
            jfieldID field = env->GetFieldID(cls, "width", "I");
            frame.width = env->functions->GetIntField(env, jframe, field);
        }
        {
            jfieldID field = env->GetFieldID(cls, "height", "J");
            frame.height = env->functions->GetLongField(env, jframe, field);
        }
    }
} // namespace t1

//=============================================================
// 场景 2,比较常见 c 风格或者 c++ 风格
namespace t2 {
#if 0

    // Frame java implement
    public class Frame {
        public int width = 0;
        public long height = 0;
    }

#endif

    class Frame {
    public:
        jint width;
        jlong height;
    };

    //=============================================================
    // 最普通,最直白

    void getFrame(JNIEnv* env, jobject jframe, Frame& frame) {
        jclass cls = env->GetObjectClass(jframe);
        {
            jfieldID field = env->GetFieldID(cls, "width", "I");
            frame.width = env->functions->GetIntField(env, jframe, field);
        }
        {
            jfieldID field = env->GetFieldID(cls, "height", "J");
            frame.height = env->functions->GetLongField(env, jframe, field);
        }
    }

    //=============================================================
    // c 风格 1

    void getField_jint(JNIEnv* env, jobject jframe, char const* name, jint* v) {
        jclass cls = env->GetObjectClass(jframe);
        jfieldID field = env->GetFieldID(cls, name, "I");
        *v = env->functions->GetIntField(env, jframe, field);
    }

    void getField_jlong(JNIEnv* env, jobject jframe, char const* name, jlong* v) {
        jclass cls = env->GetObjectClass(jframe);
        jfieldID field = env->GetFieldID(cls, name, "J");
        *v = env->functions->GetLongField(env, jframe, field);
    }

    //-------------------------

    void getFrame2(JNIEnv* env, jobject jframe, Frame& frame) {
        getField_jint(env, jframe, "width", &frame.width);
        getField_jlong(env, jframe, "height", &frame.height);
    }

    //=============================================================
    // c 风格 2

    enum FieldType{
        FT_INT,
        FT_LONG,
    };

    union Field {
        jint i;
        jlong l;
    };

    void getField(JNIEnv* env, jobject jframe, char const* name, FieldType type, Field* v) {
        jclass cls = env->GetObjectClass(jframe);
        jfieldID field;
        switch(type)
        {
            case FT_INT:
                field = env->GetFieldID(cls, name, "I");
                v->i = env->functions->GetIntField(env, jframe, field);
                break;
            case FT_LONG:
                field = env->GetFieldID(cls, name, "J");
                v->l = env->functions->GetLongField(env, jframe, field);
                break;
        }
    }

    //-------------------------

    void getFrame3(JNIEnv* env, jobject jframe, Frame& frame) {
        Field v;

        getField(env, jframe, "width", FT_INT, &v);
        frame.width = v.i;

        getField(env, jframe, "height", FT_LONG, &v);
        frame.height = v.l;
    }

    //=============================================================
    // c++ 风格

    void getField(JNIEnv* env, jobject jframe, char const* name, jint& v) {
        jclass cls = env->GetObjectClass(jframe);
        jfieldID field = env->GetFieldID(cls, name, "I");
        v = env->functions->GetIntField(env, jframe, field);
    }

    void getField(JNIEnv* env, jobject jframe, char const* name, jlong& v) {
        jclass cls = env->GetObjectClass(jframe);
        jfieldID field = env->GetFieldID(cls, name, "J");
        v = env->functions->GetLongField(env, jframe, field);
    }

    //-------------------------

    void getFrame4(JNIEnv* env, jobject jframe, Frame& frame) {
        getField(env, jframe, "width", frame.width);
        getField(env, jframe, "height", frame.height);
    }

} // namespace t2

//=============================================================
// 场景 3,现代 c++ 风格,采用范型编程实现
namespace t3 {
#if 0

    // Frame java implement
    public class Frame {
        public int width = 0;
        public long height = 0;
    }

#endif

    class Frame {
    public:
        jint width;
        jlong height;
    };

    template<typename T>
    class Field {
    public:
        static char const* SIGNATURE;
        static void GetField(JNIEnv* env, jobject obj, jfieldID field, T& v);
    };

    template<> char const* Field<jint>::SIGNATURE = "I";
    template<> inline void Field<jint>::GetField(JNIEnv* env, jobject obj, jfieldID field, jint& v) {
        v = env->functions->GetIntField(env, obj, field);
    }

    template<> char const* Field<jlong>::SIGNATURE = "J";
    template<> inline void Field<jlong>::GetField(JNIEnv* env, jobject obj, jfieldID field, jlong& v) {
        v = env->functions->GetLongField(env, obj, field);
    }

    template<typename T>
    void getField(JNIEnv* env, jobject jframe, char const* name, T& v) {
        jclass cls = env->GetObjectClass(jframe);
        jfieldID field = env->GetFieldID(cls, name, Field<T>::SIGNATURE);
        Field<T>::GetField(env, jframe, field, v);
        v = env->functions->GetIntField(env, jframe, field);
    }

    //-------------------------

    void getFrame(JNIEnv* env, jobject jframe, Frame& frame) {
        getField(env, jframe, "width", frame.width);
        getField(env, jframe, "height", frame.height);
    }

} // namespace t3