C++17中能否推导函数的模板值参数(而非类型参数)?
如何在C++17中从函数参数推导非类型模板参数
首先,你提到的错误写法template<int I = x> int bar(const int x)确实无法工作——模板参数的默认值必须是编译期可见的常量表达式,而x在模板参数声明阶段还未被定义,编译器根本不知道它的值是什么。
那C++17里有没有办法实现类似“从函数参数推导模板值参数”的需求?答案是:不能直接像推导类型参数那样从普通函数参数推导,但有几种技巧可以接近你的目标,具体取决于你想要的效果:
1. 如果你只需要常量表达式参数(不需要模板参数)
如果你的核心需求是让函数参数成为编译期可计算的常量,而非必须作为模板非类型参数,那么最简单的方式是使用constexpr函数:
constexpr int bar(int x) { // 当调用时传入编译期常量,x在这里就是常量表达式 return x; } // 编译期调用示例 constexpr int result = bar(5); // 结果在编译时就确定为5
这种方式下,只要你传递的参数是编译期常量,函数内部可以把它当作常量表达式使用(比如用于数组大小、模板参数等),但x本身不是模板参数。
2. 用编译期常量包装类型推导模板参数
如果你确实需要把参数值作为模板非类型参数(比如用来实例化其他模板),可以借助std::integral_constant这类编译期值的包装类型,让编译器推导模板参数:
#include <type_traits> // 你原有的模板函数 template<int I> int foo() { return I; } // 接受std::integral_constant,推导模板参数I template <int I> constexpr int bar(std::integral_constant<int, I>) { return foo<I>(); // 这里可以直接用I作为模板参数 } int main() { // 调用时显式传递编译期常量包装对象 constexpr int res = bar(std::integral_constant<int, 5>{}); return res; }
这种方式的本质是把值包装成类型,让编译器通过类型推导获取模板参数的值。
3. 用auto非类型模板参数简化定义
C++17支持auto作为非类型模板参数,你可以用它简化模板的定义,再配合宏减少调用时的冗余代码:
template <auto I> constexpr int bar() { return I; } // 用宏简化调用,避免手动写模板参数 #define CALL_BAR(x) bar<x>() int main() { constexpr int res = CALL_BAR(5); return res; }
这种方式虽然需要用宏,但调用起来更接近你想要的bar(5)的形式。
注意:完全自动推导需要C++20
如果你想要完全不需要额外语法,直接通过bar(5)让编译器推导模板非类型参数,那得等到C20——它引入了constexpr函数参数和更灵活的模板参数推导规则,能直接实现这种需求,但C17并不支持。
内容的提问来源于stack exchange,提问作者user7119460
相关产品推荐
相关产品推荐

