从std::make_index_sequence推导参数包为何不能用作默认参数
问题描述
为了尽可能将模板相关实现封装在代码深层,尝试将std::make_index_sequence作为函数默认参数使用,但该写法无法通过编译,无法理解其背后原因。
首先给出无默认参数的可编译示例(注:示例为简化版本,非实际业务使用场景):
#include <utility> template <std::size_t... TIndicies> std::size_t FunctNoDefaultArgs(std::index_sequence<TIndicies...>) { return (TIndicies + ... + 0); } int main() { return FunctNoDefaultArgs(std::make_index_sequence<5>{}); }
上述代码可正常编译运行。
基于上述可运行版本,尝试将std::make_index_sequence<5>{}设置为函数默认参数,编写代码如下:
#include <utility> template <std::size_t... TIndicies> std::size_t FunctDefaultArgs(std::index_sequence<TIndicies...> = std::make_index_sequence<5>{}) { return (TIndicies + ... + 0); } int main() { return FunctDefaultArgs(); }
该代码在MSVC、Clang、GCC三类主流编译器下均无法编译通过。
编译失败根本原因
C++函数模板的参数推导规则明确:模板参数推导仅依赖调用处显式传入的实参,默认参数不参与模板参数推导过程。
- 调用无参数版本
FunctDefaultArgs()时,编译器首先要完成模板参数推导,但此时没有任何传入实参可以用来确定可变模板参数包TIndicies...的具体值,直接触发推导失败错误。 - 默认参数的匹配、填充发生在模板参数推导完成之后,编译器根本不会走到检查默认参数的步骤,自然也不会从默认值
std::make_index_sequence<5>{}反推TIndicies的取值。 - 第一个可编译版本之所以能正常运行,是因为调用时显式传入了
std::make_index_sequence<5>{}实参,编译器可以直接从该实参类型推导出TIndicies...为0,1,2,3,4,后续实例化流程不存在阻碍。
可行实现方案
如果需要实现「不传参时默认使用长度为5的索引序列」的封装效果,可以通过重载实现,避免默认参数参与模板推导的问题:
#include <utility> template <std::size_t... TIndicies> std::size_t FunctImpl(std::index_sequence<TIndicies...>) { return (TIndicies + ... + 0); } // 无参重载,内部默认构造长度为5的索引序列 std::size_t FunctDefaultArgs() { return FunctImpl(std::make_index_sequence<5>{}); } // 带参重载,支持传入自定义长度的索引序列 template <std::size_t... TIndicies> std::size_t FunctDefaultArgs(std::index_sequence<TIndicies...> seq) { return FunctImpl(seq); } int main() { // 不传参默认返回0+1+2+3+4=10 return FunctDefaultArgs(); }
内容的提问来源于stack exchange,提问作者MMYC
相关产品推荐
相关产品推荐

