为何std::size_t可变参数函数SumIndices编译失败而模板SumValues可正常编译
问题原因分析
你遇到的编译错误本质是因为C++ 不允许非模板函数声明 C++ 风格的参数包,折叠表达式只能作用于模板对应的参数包。C++的参数包分为模板参数包和函数参数包,函数参数包必须绑定到对应的模板参数包才能存在,不存在脱离模板的函数参数包。普通非模板函数如果要写可变参数,只能用C风格的可变参数语法(std::size_t first, ...),这种语法的参数不能用折叠表达式展开,只能通过va_list系列接口操作,使用起来非常繁琐且没有类型安全保障。
两个函数的差异对比
SumValues是模板函数,代码中的typename ...t_data_type是模板参数包,对应的函数参数t_data_type ..._values会被编译器识别为合法的函数参数包,因此用折叠表达式展开_values是符合语法规则的。SumIndices是普通非模板函数,直接在参数列表写std::size_t ..._indices不属于合法的参数包声明语法,编译器不会将_indices识别为可展开的参数包,所以你使用折叠表达式展开时就会抛出“expansion pattern contains no parameter packs”的错误。
正确的实现方式
如果你需要实现参数固定为 std::size_t 类型的可变参数求和函数,可以选以下任意一种写法:
写法1:用模板参数包+类型约束(C++20及以上)
#include <concepts> template <std::same_as<std::size_t> ...t_indices> constexpr auto SumIndices(t_indices ..._indices) { return (_indices + ...); }
或者用更简洁的缩写函数模板写法:
#include <concepts> constexpr auto SumIndices(std::same_as<std::size_t> auto ..._indices) { return (_indices + ...); }
写法2:静态断言校验类型(兼容C++17及以上)
#include <type_traits> template <typename ...t_indices> constexpr auto SumIndices(t_indices ..._indices) { static_assert((std::is_same_v<std::size_t, t_indices> && ...), "所有参数必须为std::size_t类型"); return (_indices + ...); }
写法3:非类型模板参数包
如果你的参数都是编译期常量,也可以直接用非类型模板参数包实现:
template <std::size_t ..._indices> constexpr auto SumIndices() { return (_indices + ...); } // 调用方式:SumIndices<1,2,3>()
内容的提问来源于stack exchange,提问作者niran90
相关产品推荐
相关产品推荐

