C++如何将字符数组包展开为字符数组及索引序列的模板参数
问题解答
你想要的编译期字符串拼接效果是可以实现的,但不能直接按照你写的伪代码语法实现,C++模板规则不支持你示例中那种分组交替的参数包定义方式,以下是可行的实现思路和代码示例。
你写的伪代码的语法问题
- 模板参数列表不支持分组嵌套的可变参数包,
template <char const *S0, size_t... I0, char const *S1, size_t... I1, ...>的写法不符合C++语法,可变参数包只能放在模板参数列表末尾,无法重复交替声明多组不同的参数包。 - 函数形参
strs属于运行期参数,不能直接作为模板非类型参数传递,C++要求非类型指针模板参数必须指向具有静态存储期的对象。
可行实现方案(C++20及以上)
我们可以通过辅助结构先把每个字符串和对应的索引序列打包,再展开拼接:
#include <utility> #include <tuple> // 辅助结构:包装单个字符串和对应的索引序列(去掉末尾的\0,所以索引序列长度是L-1) template<const char* Str, typename Seq> struct str_pack {}; // 将输入的所有字符串和对应索引序列打包 template<size_t... L> constexpr auto pack_all_str(const char (&...strs)[L]) { return std::make_tuple(str_pack<strs, std::make_index_sequence<L-1>>{}...); } // 拼接逻辑实现 template<typename... Packs> struct combine_impl; // 递归终止:单个字符串包 template<const char* Str, size_t... Is> struct combine_impl<str_pack<Str, std::index_sequence<Is...>>> { constexpr static char value[] = {Str[Is]..., '\0'}; }; // 递归拼接多个字符串包 template<const char* S0, size_t... I0, const char* S1, size_t... I1, typename... Rest> struct combine_impl<str_pack<S0, std::index_sequence<I0...>>, str_pack<S1, std::index_sequence<I1...>>, Rest...> { constexpr static char value[] = {S0[I0]..., S1[I1]..., combine_impl<Rest...>::value..., '\0'}; }; // 对外调用接口 template<size_t... L> constexpr const char* combine_str(const char (&...strs)[L]) { return combine_impl<decltype(pack_all_str(strs))...>::value; } // 使用示例 constexpr const char a[] = "hello"; constexpr const char b[] = "world"; constexpr auto res = combine_str(a, b); // 编译期得到"helloworld"
更简洁的constexpr函数实现(C++17及以上)
如果不需要严格用模板参数展开的形式实现,直接用constexpr函数拼接的写法更简洁,编译期也能得到相同的效果:
#include <array> #include <string_view> template<size_t... L> constexpr auto combine_str(const char (&...strs)[L]) { constexpr size_t total_len = (L + ...) - sizeof...(L); // 减去每个字符串末尾的\0长度 std::array<char, total_len + 1> arr{}; size_t pos = 0; (([&] { for (size_t i = 0; i < L - 1; i++) arr[pos++] = strs[i]; }()), ...); arr[total_len] = '\0'; return arr; } // 使用示例 constexpr auto res = combine_str("hello", "world"); static_assert(res.data() == std::string_view("helloworld"));
内容的提问来源于stack exchange,提问作者Meekaa Saangoo
相关产品推荐
相关产品推荐

