编译期获取多个C字符串最大长度的问题及扩展需求
问题1:修复可变参constexpr函数的编译错误
你的代码报错是因为在C++17中,函数参数不能作为常量表达式的一部分——你在constexpr uint32_t lengths [] = {get_string_length(strs)...};里用了函数参数strs,这不符合常量表达式的要求。
其实根本不需要get_string_length函数,模板参数N已经直接给出了数组的长度(包含末尾的\0),直接用N即可。修改后的代码如下:
#include <cstdint> template <uint32_t... N> constexpr uint32_t max_string_length_all(const char (&... strs)[N]) { uint32_t max_len = 0; // 用折叠表达式遍历所有N,直接比较更新最大值 ((max_len = N > max_len ? N : max_len), ...); return max_len; } // 调用示例 inline constexpr char const my_string_0[] = "my string 0"; inline constexpr char const my_string_1[] = "longer string example"; inline constexpr char const my_string_3[] = "short"; constexpr uint32_t max = max_string_length_all(my_string_0, my_string_1, my_string_3); // max的值会是23(对应"longer string example"的长度+1)
如果更习惯循环写法,C++17允许constexpr函数里用范围for,只需调整数组初始化方式:
template <uint32_t... N> constexpr uint32_t max_string_length_all(const char (&... strs)[N]) { const uint32_t lengths[] = {N...}; // 用const而非constexpr,避免函数参数的常量表达式限制 uint32_t max_len = 0; for (uint32_t len : lengths) { if (len > max_len) { max_len = len; } } return max_len; }
注意:把字符串声明为constexpr能确保编译期可见性,更稳妥。
问题2:从结构体数组编译期获取最大字符串长度
可行,但需要满足两个前提:
- 原始字符串数组必须是编译期可见的常量(比如
constexpr或static const),不能是运行时赋值的指针; - 结构体数组也需要是
constexpr,才能在编译期遍历。
实现代码(C++17兼容)
#include <cstdint> // 辅助模板:获取字符串数组的长度 template <uint32_t N> constexpr uint32_t get_str_len(const char (&)[N]) noexcept { return N; } // 编译期遍历数组的递归模板 template <typename T, uint32_t Size, uint32_t Index = 0> struct MaxStrLenInArray { static constexpr uint32_t value = get_str_len(*static_cast<const std::remove_pointer_t<decltype(std::declval<const T>().my_string)>*>(std::declval<const T>().my_string)) > MaxStrLenInArray<T, Size, Index + 1>::value ? get_str_len(*static_cast<const std::remove_pointer_t<decltype(std::declval<const T>().my_string)>*>(std::declval<const T>().my_string)) : MaxStrLenInArray<T, Size, Index + 1>::value; }; // 递归终止条件 template <typename T, uint32_t Size> struct MaxStrLenInArray<T, Size, Size> { static constexpr uint32_t value = 0; }; // 包装成函数,方便调用 template <typename T, uint32_t Size> constexpr uint32_t max_str_len_in_struct_array(const T (&arr)[Size]) noexcept { return MaxStrLenInArray<T, Size>::value; } // 使用示例 struct T_my_struct { const char* my_string; int some_data; // 其他结构体成员 }; // 原始字符串必须是constexpr,确保编译期能获取长度 constexpr char const my_string_0[] = "my string 0"; constexpr char const my_string_1[] = "longer string example"; constexpr char const my_string_2[] = "short"; // 结构体数组也必须是constexpr constexpr T_my_struct my_array[] = { {my_string_0, 10}, {my_string_1, 20}, {my_string_2, 30} }; // 编译期计算最大长度 constexpr uint32_t max_len = max_str_len_in_struct_array(my_array); // max_len的值为23
C++20简化版本
如果编译器支持C++20,可用constexpr lambda和范围for替代递归:
#include <cstdint> #include <type_traits> template <typename T, uint32_t Size> constexpr uint32_t max_str_len_in_struct_array(const T (&arr)[Size]) noexcept { uint32_t max_len = 0; constexpr auto get_len = []<uint32_t N>(const char (&)[N]) { return N; }; for (const auto& elem : arr) { // 转换回原始数组类型以推导长度 using StrArrType = std::remove_pointer_t<decltype(elem.my_string)>; auto len = get_len(*static_cast<const StrArrType*>(elem.my_string)); if (len > max_len) max_len = len; } return max_len; }
注意:如果结构体里的my_string指向运行时分配的内存,编译期无法获取长度——但你的微控制器场景用的是C字符串数组,完全满足编译期推导的要求。
内容的提问来源于stack exchange,提问作者Martin_from_K
相关产品推荐
相关产品推荐

