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

如何移除C++中手动索引的大括号列表样板代码?

解决方案

要同时保留手动定义单个数组(如A0、A1)的便捷性,又消除A[]、x[]、b[]的样板代码,可以借助预处理器宏来自动生成指针数组的初始化列表。由于每个派生类(如BaseCat、BaseDog)的n值在编写代码时是固定的,这种方法完全可行。

步骤1:定义生成指针列表的宏

首先,为常用的n值(如2、3、4、24等)定义宏,用于生成对应数量的指针列表:

// 基础宏:生成单个指针项
#define GEN_PTR_ITEM(name, idx) name##idx

// 为不同n值定义指针列表宏
#define GEN_PTR_LIST_2(name) GEN_PTR_ITEM(name, 0), GEN_PTR_ITEM(name, 1)
#define GEN_PTR_LIST_3(name) GEN_PTR_LIST_2(name), GEN_PTR_ITEM(name, 2)
#define GEN_PTR_LIST_4(name) GEN_PTR_LIST_3(name), GEN_PTR_ITEM(name, 3)
// ... 按需扩展到n=24的版本:
#define GEN_PTR_LIST_24(name) GEN_PTR_LIST_23(name), GEN_PTR_ITEM(name, 23)

// 最终宏:生成完整的指针数组声明
#define GEN_PTR_ARRAY(name, n) double* name[] = { GEN_PTR_LIST_##n(name) }

步骤2:在派生类中使用宏

保留原有的单个数组定义,并用宏替代样板代码:

template<size_t n> class Base{
public:
    static constexpr size_t n_ = n;
};

class BaseCat: protected Base<4>{
private:
    // 保留原有的便捷初始化方式
    double A0[] = {0,1,2,3,4,5,6,7,8,9};
    double A1[] = {13,-2};
    double A2[] = {4.5, 6.7, 8.9};
    double A3[] = {-1, -2, -3, -4};

    double x0[] = {1,0};
    double x1[] = {0,1};
    double x2[] = {1,1};
    double x3[] = {0,0};

    double b0[] = {0};
    double b1[] = {1};
    double b2[] = {2};
    double b3[] = {3};

protected:
    // 用宏替代样板代码
    GEN_PTR_ARRAY(A, 4)
    GEN_PTR_ARRAY(x, 4)
    GEN_PTR_ARRAY(b, 4)
};

using DerivedCat = Derived<BaseCat, BaseCat::n_>;

替代方案:CRTP + 元组(C++17及以上)

如果你愿意调整单个数组的声明方式,可以使用CRTP(奇异递归模板模式)结合std::tuple来完全消除样板代码,无需宏:

#include <tuple>
#include <array>
#include <utility>

template<size_t n, typename Derived>
class Base{
public:
    static constexpr size_t n_ = n;

protected:
    double* A[n];
    double* x[n];
    double* b[n];

    Base(){
        auto& derived = *static_cast<Derived*>(this);
        // 利用索引序列自动初始化指针数组
        [&]<size_t... Is>(std::index_sequence<Is...>) {
            ((A[Is] = std::get<Is>(derived.A_tuple).data()), ...);
            ((x[Is] = std::get<Is>(derived.x_tuple).data()), ...);
            ((b[Is] = std::get<Is>(derived.b_tuple).data()), ...);
        }(std::make_index_sequence<n>{});
    }
};

class BaseCat: protected Base<4, BaseCat>{
private:
    // 将单个数组放入元组中,保持初始化便捷性
    std::tuple<
        std::array<double, 10>,
        std::array<double, 2>,
        std::array<double, 3>,
        std::array<double, 4>
    > A_tuple = {
        {0,1,2,3,4,5,6,7,8,9},
        {13,-2},
        {4.5,6.7,8.9},
        {-1,-2,-3,-4}
    };

    std::tuple<
        std::array<double,2>,
        std::array<double,2>,
        std::array<double,2>,
        std::array<double,2>
    > x_tuple = {
        {1,0}, {0,1}, {1,1}, {0,0}
    };

    std::tuple<
        std::array<double,1>,
        std::array<double,1>,
        std::array<double,1>,
        std::array<double,1>
    > b_tuple = {
        {0}, {1}, {2}, {3}
    };

    // 无需手动声明A[]、x[]、b[],由Base构造器自动初始化
};

using DerivedCat = Derived<BaseCat, BaseCat::n_>;

这种方案虽然需要将数组放入元组,但完全避免了样板代码,且类型更安全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:04:57