如何基于编译期分支返回不同大小的std::array?
问题原因分析
你的代码编译失败的核心原因是:非模板上下文里的constexpr-if非活动分支,并非完全不做语义检查。
当PRODUCT为ProductType::A时,dataSize()返回3,此时constexpr-if的第一个分支是被丢弃的,但你在该分支里显式构造了std::array<int, dataSize()> {1,2,3,4}——这里的dataSize()会被立即求值为3,相当于试图用4个元素初始化大小为3的std::array,这是明确的语义错误,编译器必须报错,哪怕这个分支永远不会执行。
constexpr-if的“跳过非活动分支检查”规则,主要针对模板上下文(比如依赖模板参数的代码),此时非活动分支的代码会被延迟实例化。但在非模板的constexpr函数中,所有代码都处于非依赖上下文,编译器会检查所有代码的语法和语义合法性,除非表达式不会被实际求值(比如sizeof()内部的表达式)。
修复方案
以下几种方式可以解决这个问题:
方案1:直接返回初始化列表
不需要显式构造std::array,直接返回与函数返回类型匹配的初始化列表。编译器只会在活动分支验证列表的合法性,丢弃分支的列表不会被检查:
constexpr std::array<int, dataSize()> createArray() { if constexpr (dataSize() == 4) { return {1, 2, 3, 4}; } else { return {1, 2, 3}; } }
方案2:先初始化数组再赋值
先创建一个默认初始化的返回类型数组,再在对应分支中完成赋值操作,确保所有分支操作的都是同一类型的数组:
constexpr std::array<int, dataSize()> createArray() { std::array<int, dataSize()> arr{}; if constexpr (dataSize() == 4) { arr = {1, 2, 3, 4}; } else { arr = {1, 2, 3}; } return arr; }
方案3:绑定返回类型别名
先定义与函数返回类型一致的别名,在分支中使用该别名构造数组,避免显式计算模板参数:
constexpr std::array<int, dataSize()> createArray() { using ReturnArray = std::array<int, dataSize()>; if constexpr (dataSize() == 4) { return ReturnArray{1, 2, 3, 4}; } else { return ReturnArray{1, 2, 3}; } }
内容的提问来源于stack exchange,提问作者Avi Shukron
相关产品推荐
相关产品推荐

