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

如何让Vec<C>通过初始化列表推导模板参数为std::array<T,N>?

问题:让Vec<C>支持花括号列表推导为std::array<T,N>

我定义了如下的Vec<C>类,需要编写构造函数和/或推导指南,使得花括号包裹的初始化列表能将模板参数C推导为std::array<T,N>。由于无需提前知晓大小,std::vector<T>可以正常适配该类。

#include <cassert>
#include <iostream>
#include <array>
#include <vector>
#include <concepts>
#include <type_traits>

template<typename T>
concept has_resize = requires(T t)
{
    {t.resize(0)};
};

template<typename C>
class Vec
{
    C elems;
public:
    template<typename IndexType> 
    requires std::integral<IndexType> && std::is_unsigned_v<IndexType>
    auto operator[](IndexType i) const 
    { 
         return elems[i];
    }
    auto size()               const { return elems.size(); }
    template<typename T>
    Vec(std::initializer_list<T> init)//MEMBER INITIALIZER LIST?
    {
        // WHAT CODE GOES HERE?
    }
    Vec(auto init)
    {
        if constexpr (has_resize<decltype(elems)>) 
            elems.resize(init.size());
        for (decltype(init.size()) i = 0; i<init.size() ; i++)
            elems[i] = init[i];
    }
};

template<typename C>
Vec(C) -> Vec<C>;

//WHAT'S THE CORRECT DEDUCTION GUIDE?

int main()
{
    Vec v0({1, 4, 7});
    Vec v1(std::array<int,3>{2, 5, 8});
    Vec v2(std::vector<double>{3, 6, 9});
}

编辑1:不能修改Vec v0({1, 4, 7});或Vec v0{1, 4, 7};这类调用方式。
编辑2:template<typename T> Vec(const std::initializer_list<T>& vec) -> Vec<std::array<T, vec.size()>>;无法正常工作。
编辑3:本问题与Stack Overflow上的“Template class and automatic deduction”相关,可作为推导指南用法的补充示例。


解决方案

核心问题是std::initializer_list的size是运行时属性,无法用于推导std::array的编译期大小N。因此需要用模板参数包捕获初始化列表元素,在编译期确定元素数量,进而推导std::array类型。

修改后的完整代码

#include <cassert>
#include <iostream>
#include <array>
#include <vector>
#include <concepts>
#include <type_traits>

template<typename T>
concept has_resize = requires(T t)
{
    {t.resize(0)};
};

template<typename C>
class Vec
{
    C elems;
public:
    template<typename IndexType> 
    requires std::integral<IndexType> && std::is_unsigned_v<IndexType>
    auto operator[](IndexType i) const 
    { 
         return elems[i];
    }
    auto size()               const { return elems.size(); }

    // 处理花括号初始化:用模板参数包接收元素
    template<typename... Ts>
    requires (std::same_as<Ts, std::common_type_t<Ts...>> && ...)
    Vec(Ts&&... args) : elems{std::forward<Ts>(args)...} {}

    // 处理已有容器(如std::array、std::vector),排除初始化列表避免冲突
    template<typename Container>
    requires (!std::is_initializer_list_v<std::decay_t<Container>>)
    Vec(Container&& init)
    {
        if constexpr (has_resize<decltype(elems)>) 
            elems.resize(init.size());
        for (decltype(init.size()) i = 0; i < init.size(); i++)
            elems[i] = init[i];
    }
};

// 推导指南:从参数包推导为std::array,编译期确定大小
template<typename... Ts>
Vec(Ts&&...) -> Vec<std::array<std::common_type_t<Ts...>, sizeof...(Ts)>>;

// 推导指南:从已有容器推导为对应容器类型
template<typename Container>
Vec(Container&&) -> Vec<std::decay_t<Container>>;

int main()
{
    Vec v0({1, 4, 7}); // 推导为Vec<std::array<int, 3>>
    Vec v1(std::array<int,3>{2, 5, 8}); // 推导为Vec<std::array<int,3>>
    Vec v2(std::vector<double>{3, 6, 9}); // 推导为Vec<std::vector<double>>

    // 验证类型正确性
    static_assert(std::same_as<decltype(v0), Vec<std::array<int,3>>>);
    static_assert(std::same_as<decltype(v1), Vec<std::array<int,3>>>);
    static_assert(std::same_as<decltype(v2), Vec<std::vector<double>>>);

    // 验证功能正常
    std::cout << v0.size() << " " << v1.size() << " " << v2.size() << "\n"; // 输出3 3 3
    std::cout << v0[0] << " " << v1[1] << " " << v2[2] << "\n"; // 输出1 5 9
}

关键要点

  1. 模板参数包构造函数:直接用参数包初始化内部elems,requires约束确保所有元素类型一致,避免异构类型错误。
  2. 编译期推导std::array大小:推导指南中用sizeof...(Ts)获取编译期元素数量,std::common_type_t处理类型统一(如混合int和long时自动兼容)。
  3. 避免构造函数冲突:给容器构造函数添加!std::is_initializer_list_v约束,确保花括号初始化走参数包分支,容器初始化走对应分支。
  4. 兼容原有容器推导:保留容器类型的推导指南,确保std::array和std::vector能正常推导为对应的Vec<C>类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 22:23:11