c++:连接从模板参数生成的字符串文字

问题描述 投票:0回答:0

我想根据模板参数的变量数量的类型生成一个字符串文字。应将每种类型转换为字符串文字(1 个或多个字符),然后将文字连接起来。例如:

const char* sig1 = make_sig<void, int>();
assert(strcmp("VI", sig1) == 0); // with void=>"V", int=>"I"

const char* sig2 = make_sig<void, int, bool>();
assert(strcmp("VIZ", sig2) == 0); // with bool=>"Z"

用例:在使用 JNI 运行时注册本机方法时,自动从 C/C++ 函数声明生成 JNI(Java 本机接口)签名,而不是手写签名,因为它们会变得复杂:

typedef struct {
    const char *signature;
    // ...
} JNINativeMethod;

JNINativeMethod methods[] = {
    { sig1 }, // I want string literals to assign to a const char*
    { sig2 },
};

jniEnv->RegisterMethods(methods, sizeof(methods)/sizeof(methods[0]);

如何在 C++17 中实现这个

make_sig()
模板函数?

到目前为止我对编译时字符串的了解:

template<char...s>
struct string_holder {
    static constexpr char value[] = { s..., '\0' };
};

template <typename...Ts>
struct concat;

template <char...s>
struct concat<string_holder<s...>> : public string_holder<s...> {};

template <char...s1, char...s2>
struct concat<string_holder<s1...>, string_holder<s2...>> : public string_holder<s1..., s2...> {};


template <typename T> struct as_jni;
template <> struct as_jni<void> { using type = string_holder<'V'>; };
template <> struct as_jni<int> { using type = string_holder<'I'>; };

template <typename...Ts>
const char* make_sig() {
    return concat<typename as_jni<Ts>::type...>::value;
}

assert(strcmp(make_sig<int, void>(), "IV") == 0);

但这并不能扩展到任意数量的模板参数:

make_sig<int, void, int>(); // compile error: implicit instantiation of undefined template

我有一个将 JNI 签名生成为

std::string
的解决方案,但我更喜欢文字。

struct jstring {};
template <typename T> const char* to_jni_type();
template <> const char* to_jni_type<void>() { return "V"; }
template <> const char* to_jni_type<int>() { return "I"; }
template <> const char* to_jni_type<jstring>() { return "Ljava/lang/String;"; }

template <typename Last = void>
std::string type_sig() {
    return to_jni_type<Last>();
}

template <typename First, typename Second, typename ...Rest>
std::string type_sig() {
    return type_sig<First>() + type_sig<Second, Rest...>();
}

template <typename Ret, typename ...Args>
std::string make_sig(Ret(*)(Args...)) {
    return '(' + type_sig<Args...>() + ')' + type_sig<Ret>();
}

void native(int, jstring);

assert("(ILjava/lang/String;)V" == make_sig(native));

对我没有帮助的相关问题:

c++ c++17 variadic-templates template-meta-programming string-literals
© www.soinside.com 2019 - 2024. All rights reserved.