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

C++17及更早版本中带默认值的数组模板参数替代方案

兼容C++17及更早版本的3D空间隐式索引访问器模板实现方案

针对你需要的编译期3D空间索引转换访问器,在无法使用C20 std::array 默认模板参数的情况下,以下两种方案可以实现和C20方案同等的可读性,同时兼容C++17及更早版本:

方案一:标签式参数分组模板

将原点、填充、分块这三类语义相关的参数,分别用独立的模板标签结构体打包,主模板接收这些标签作为参数并提供默认值,既保留参数语义,又避免零散的模板参数列表。

实现代码

// 标签结构体:用于分组语义相关的编译期参数
template<int X = 0, int Y = 0, int Z = 0>
struct Origin {};

template<int Left = 0, int Right = 0, int Top = 0, int Bottom = 0, int Front = 0, int Back = 0>
struct Padding {};

template<int SizeX = 1, int SizeY = 1, int SizeZ = 1>
struct Block {};

// 主访问器模板
template<typename OriginTag = Origin<>, typename PaddingTag = Padding<>, typename BlockTag = Block<>>
struct Implicit3DIndexAccessor {
    // 辅助模板:提取标签中的参数值
    template<typename T> struct GetOrigin;
    template<int X, int Y, int Z> struct GetOrigin<Origin<X,Y,Z>> {
        static constexpr int x = X;
        static constexpr int y = Y;
        static constexpr int z = Z;
    };

    template<typename T> struct GetPadding;
    template<int L, int R, int T, int B, int F, int Ba> struct GetPadding<Padding<L,R,T,B,F,Ba>> {
        static constexpr int left = L;
        static constexpr int right = R;
        static constexpr int top = T;
        static constexpr int bottom = B;
        static constexpr int front = F;
        static constexpr int back = Ba;
    };

    template<typename T> struct GetBlock;
    template<int X, int Y, int Z> struct GetBlock<Block<X,Y,Z>> {
        static constexpr int size_x = X;
        static constexpr int size_y = Y;
        static constexpr int size_z = Z;
    };

    // 导出编译期常量参数
    static constexpr int origin_x = GetOrigin<OriginTag>::x;
    static constexpr int origin_y = GetOrigin<OriginTag>::y;
    static constexpr int origin_z = GetOrigin<OriginTag>::z;

    static constexpr int pad_left = GetPadding<PaddingTag>::left;
    static constexpr int pad_right = GetPadding<PaddingTag>::right;
    static constexpr int pad_top = GetPadding<PaddingTag>::top;
    static constexpr int pad_bottom = GetPadding<PaddingTag>::bottom;
    static constexpr int pad_front = GetPadding<PaddingTag>::front;
    static constexpr int pad_back = GetPadding<PaddingTag>::back;

    static constexpr int block_size_x = GetBlock<BlockTag>::size_x;
    static constexpr int block_size_y = GetBlock<BlockTag>::size_y;
    static constexpr int block_size_z = GetBlock<BlockTag>::size_z;

    // 核心索引转换逻辑示例
    template<int X, int Y, int Z>
    static constexpr size_t convert_index() {
        int adjusted_x = X - origin_x + pad_left;
        int adjusted_y = Y - origin_y + pad_top;
        int adjusted_z = Z - origin_z + pad_front;
        // 此处根据实际分块逻辑调整计算方式
        return (adjusted_z / block_size_z) * ((pad_left + pad_right) / block_size_x) * ((pad_top + pad_bottom) / block_size_y)
             + (adjusted_y / block_size_y) * ((pad_left + pad_right) / block_size_x)
             + (adjusted_x / block_size_x);
    }
};

使用示例

// 使用全部默认参数(原点(0,0,0)、无填充、块大小1x1x1)
using DefaultAccessor = Implicit3DIndexAccessor<>;

// 自定义原点、填充和分块参数
using CustomAccessor = Implicit3DIndexAccessor<Origin<5,5,5>, Padding<2,2,2,2,2,2>, Block<4,4,4>>;

// 编译期计算转换后的索引
constexpr auto idx = CustomAccessor::convert_index<10,10,10>();

方案二:编译期参数结构体+模板特化

定义一个包含所有参数的编译期结构体,主模板接收该结构体类型作为参数并提供默认实现,参数集中管理,代码更简洁。

实现代码

// 默认参数结构体:所有参数的默认值
struct Default3DParams {
    static constexpr int origin_x = 0;
    static constexpr int origin_y = 0;
    static constexpr int origin_z = 0;

    static constexpr int pad_left = 0;
    static constexpr int pad_right = 0;
    static constexpr int pad_top = 0;
    static constexpr int pad_bottom = 0;
    static constexpr int pad_front = 0;
    static constexpr int pad_back = 0;

    static constexpr int block_size_x = 1;
    static constexpr int block_size_y = 1;
    static constexpr int block_size_z = 1;
};

// 辅助宏(可选):简化自定义参数结构体的定义
#define DEFINE_3D_PARAMS(Name, Ox, Oy, Oz, Pl, Pr, Pt, Pb, Pf, Pb_, Bsx, Bsy, Bsz) \
struct Name { \
    static constexpr int origin_x = Ox; \
    static constexpr int origin_y = Oy; \
    static constexpr int origin_z = Oz; \
    static constexpr int pad_left = Pl; \
    static constexpr int pad_right = Pr; \
    static constexpr int pad_top = Pt; \
    static constexpr int pad_bottom = Pb; \
    static constexpr int pad_front = Pf; \
    static constexpr int pad_back = Pb_; \
    static constexpr int block_size_x = Bsx; \
    static constexpr int block_size_y = Bsy; \
    static constexpr int block_size_z = Bsz; \
}

// 自定义参数示例
DEFINE_3D_PARAMS(Custom3DParams, 5,5,5, 2,2,2,2,2,2, 4,4,4);

// 主访问器模板
template<typename Params = Default3DParams>
struct Implicit3DIndexAccessor {
    // 直接复用参数结构体中的编译期常量
    static constexpr int origin_x = Params::origin_x;
    static constexpr int origin_y = Params::origin_y;
    static constexpr int origin_z = Params::origin_z;

    static constexpr int pad_left = Params::pad_left;
    static constexpr int pad_right = Params::pad_right;
    static constexpr int pad_top = Params::pad_top;
    static constexpr int pad_bottom = Params::pad_bottom;
    static constexpr int pad_front = Params::pad_front;
    static constexpr int pad_back = Params::pad_back;

    static constexpr int block_size_x = Params::block_size_x;
    static constexpr int block_size_y = Params::block_size_y;
    static constexpr int block_size_z = Params::block_size_z;

    // 核心索引转换逻辑示例
    template<int X, int Y, int Z>
    static constexpr size_t convert_index() {
        int adjusted_x = X - origin_x + pad_left;
        int adjusted_y = Y - origin_y + pad_top;
        int adjusted_z = Z - origin_z + pad_front;
        // 此处根据实际分块逻辑调整计算方式
        return (adjusted_z / block_size_z) * ((pad_left + pad_right) / block_size_x) * ((pad_top + pad_bottom) / block_size_y)
             + (adjusted_y / block_size_y) * ((pad_left + pad_right) / block_size_x)
             + (adjusted_x / block_size_x);
    }
};

使用示例

// 使用默认参数
using DefaultAccessor = Implicit3DIndexAccessor<>;

// 使用自定义参数结构体
using CustomAccessor = Implicit3DIndexAccessor<Custom3DParams>;

// 编译期计算转换后的索引
constexpr auto idx = CustomAccessor::convert_index<10,10,10>();

方案对比

  • 标签分组方案:参数语义划分清晰,修改单个分组参数时无需重新定义整个参数集合,适合参数组合频繁变化的场景。
  • 结构体参数方案:参数集中管理,代码更简洁,适合参数组合相对固定的场景。

内容的提问来源于stack exchange,提问作者比尔盖子

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 04:11:01