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

C++ JsonPointer类:initializer_list constexpr初始化与模板尺寸推导

JsonPointer类的constexpr初始化与扩展构造函数实现

需求与现有代码

需要实现一个封装std::array的JsonPointer模板类,满足:

  • 支持通过std::initializer_list进行constexpr初始化
  • 提供构造函数/方法,接收现有JsonPointer实例和一个后缀字符串,生成尺寸为原实例尺寸+1的新实例

现有代码如下:

#include <stddef.h>
#include <array>
#include <initializer_list>

template<size_t L>
class JsonPointer {
public:
   constexpr JsonPointer(std::array<const char*, L> segments)
        : m_path_segments(std::move(segments))
    {
    }

    constexpr JsonPointer(std::initializer_list<const char*> list) : m_path_segments(std::array<const char*, list.size()>)
    {
    }

    template<size_t S>
    JsonPointer(JsonPointer<S> existing, const char* suffix)  {
    }

private:
    std::array<const char*, L> m_path_segments;
};

int main(){
    constexpr JsonPointer base_ptr {"a", "n"};
    auto ptr = JsonPointer(base_ptr, "test");
}

问题解答

1. 利用std::initializer_list的大小实现constexpr初始化

原代码的问题在于:无法从initializer_list推导模板参数L,且未完成列表元素到内部数组的拷贝。解决步骤:

  • 添加模板推导指引,让编译器从初始化列表的元素数量自动推导L
  • 在constexpr构造函数中,通过循环(C17+支持constexpr循环)或std::copy_n(C20+支持constexpr版本)完成元素拷贝,同时用static_assert确保列表大小与L匹配

2. 让模板推导识别新实例尺寸L = S + 1

原构造函数无法让编译器推导L的值,因为L是类模板参数,无法直接从构造函数参数推导。解决方式有两种:

  • 提供append成员函数,直接返回JsonPointer<S+1>类型,编译器可明确推导返回值
  • 为构造函数添加推导指引,明确声明L = S + 1

修改后的完整代码

#include <stddef.h>
#include <array>
#include <initializer_list>

template<size_t L>
class JsonPointer {
public:
    // 从std::array构造
    constexpr JsonPointer(std::array<const char*, L> segments)
        : m_path_segments(std::move(segments))
    {
    }

    // 从std::initializer_list构造:constexpr拷贝元素(兼容C++17)
    constexpr JsonPointer(std::initializer_list<const char*> list)
    {
        static_assert(list.size() == L, "Initializer list size mismatch with JsonPointer length");
        size_t idx = 0;
        for (const char* str : list) {
            m_path_segments[idx++] = str;
        }
    }

    // 方式一:通过成员函数生成尺寸+1的新实例
    constexpr JsonPointer<L + 1> append(const char* suffix) const
    {
        std::array<const char*, L + 1> new_segments{};
        // 拷贝原数组元素
        size_t idx = 0;
        for (const char* str : m_path_segments) {
            new_segments[idx++] = str;
        }
        // 添加后缀
        new_segments[L] = suffix;
        return JsonPointer<L + 1>(new_segments);
    }

    // 方式二:通过构造函数生成,配合下方推导指引
    template<size_t S>
    constexpr JsonPointer(JsonPointer<S> existing, const char* suffix)
    {
        static_assert(L == S + 1, "New JsonPointer length must be S+1");
        // 拷贝原实例元素
        size_t idx = 0;
        for (const char* str : existing.m_path_segments) {
            m_path_segments[idx++] = str;
        }
        // 添加后缀
        m_path_segments[S] = suffix;
    }

private:
    std::array<const char*, L> m_path_segments;
    // 让构造函数能访问其他实例的私有成员
    template<size_t> friend class JsonPointer;
};

// 推导指引1:从初始化列表推导L
template<typename... Args>
JsonPointer(Args&&... args) -> JsonPointer<sizeof...(Args)>;

// 推导指引2:从现有实例+后缀推导L=S+1
template<size_t S>
JsonPointer(JsonPointer<S>, const char*) -> JsonPointer<S + 1>;

int main(){
    // 从initializer_list构造,自动推导L=2
    constexpr JsonPointer base_ptr {"a", "n"};
    
    // 使用append成员函数生成L=3的实例
    auto ptr1 = base_ptr.append("test");
    
    // 使用构造函数生成L=3的实例(依赖推导指引)
    auto ptr2 = JsonPointer(base_ptr, "test");
}

关键改动说明

  • constexpr初始化:通过constexpr循环完成元素拷贝,推导指引让编译器能从初始化列表的元素数量自动匹配模板参数L
  • 尺寸推导:append成员函数直接返回JsonPointer<L+1>,或通过构造函数推导指引明确L=S+1,两种方式都能让编译器正确识别新实例的尺寸

内容的提问来源于stack exchange,提问作者Curunir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 14:33:38