You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编译期获取多个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:从结构体数组编译期获取最大字符串长度

可行,但需要满足两个前提:

  1. 原始字符串数组必须是编译期可见的常量(比如constexpr或static const),不能是运行时赋值的指针;
  2. 结构体数组也需要是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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 14:53:22