为何在模板参数场景中constexpr与const不能互换?
为什么模板参数中constexpr与const不能互换?
我查阅过一些关于constexpr的资料,理解constexpr表示可在编译期完全确定的内存位置(对象、函数等)。但在以下模板代码中,尝试将模板头的const替换为constexpr时会编译报错,而用const则能正常运行。
示例代码
code.h
#ifndef CODE_H #define CODE_H #include<vector> #include<numeric> #include<cstddef> #include<algorithm> #include<iostream> using std::vector; using std::iota; using std::size_t; using std::for_each; using std::cout; using std::endl; //template<typename T, constexpr size_t s, constexpr T min> template<typename T, const size_t s, const T min> class obj{ public: obj(); obj(const obj&)=delete; obj& operator=(const obj&)=delete; void print(); protected: private: vector<T>v = vector<T>(s); }; //template<typename T, constexpr size_t s, constexpr T min> template<typename T, const size_t s, const T min> obj<T,s,min>::obj(){ iota(v.begin(), v.end(), min); } //template<typename T, constexpr size_t s, constexpr T min> template<typename T, const size_t s, const T min> void obj<T,s,min>::print(){ for_each(v.begin(), v.end(), [](const T& t){cout << t << " ";}); cout << endl; return; } #endif
main.cpp
#include "code.h" int main (){ obj<int,5,0> V; V.print(); return 0; }
编译报错信息
将模板头替换为constexpr版本后,用g++ 11.3.1开启-Wfatal-errors和-std=c++17编译时,会报如下错误:
In file included from main.c:1: code.h:17:22: error: a parameter cannot be declared ‘constexpr’ 17 | template<typename T, constexpr size_t s, constexpr T min> | ^~~~~~~~~ compilation terminated due to -Wfatal-errors.
原因解析
1. 模板非类型参数的本质要求
模板实例化是编译期行为,因此所有非类型模板参数本身就必须是编译期可求值的常量表达式——这是C++语言的强制规则,不需要额外用constexpr声明。比如示例中obj<int,5,0>的5和0,本身就是编译期常量,完全符合要求;如果传入运行时才能确定的值(比如int x; std::cin >> x; obj<int,x,0> V;),编译器本来就会直接报错,根本不需要额外限制。
2. const在模板参数中的作用
示例里的const size_t s其实是冗余的:模板非类型参数本身就是不可修改的右值,加上const只是显式强调参数在模板内部不可修改,但即使不加const,你也无法修改模板参数的值。所以这个const加不加都不影响编译,只是代码风格层面的明确。
3. constexpr不能用于模板参数声明的语法规则
C++标准明确规定,模板参数的修饰符中不允许出现constexpr关键字。constexpr的作用是修饰变量、函数等,表明它们可以在编译期求值,但模板非类型参数已经被强制要求是编译期常量,因此既不需要也不允许用constexpr来修饰。编译器的报错正是因为违反了这个语法规则,和逻辑需求无关。
内容的提问来源于stack exchange,提问作者Vinod
相关产品推荐
相关产品推荐

