I have looked at some of the previous posts related to constexpr
, especially this one:
What's the difference between constexpr and const?
My understanding based on reading on the topic is that constexpr
denotes a memory location (object, function et al.) that can be determined fully at compile-time.
Consider the following simple code:
//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;
}
In code.h
above, if I were to substitute the template header with the template header using constexpr
(commented out in the code), the compilation stops at the first encounter of the template header, with g++ 11.3.1
using -Wfatal-errors
and -std=c++17
, with the following error:
I
n 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.
Note that I am using constexpr 5
and constexpr 0
in main.c for initializing the template. My idea of using constexpr
in the template header is to restrict the user of the template to using compile-time constants in initializing the template. If I were to use const
instead, the code compiles and runs with the expected output.
So, why isn't constexpr
interchangeable with const
in this instance?
constexpr
is not permitted on function or template parameters, only top-level on variable and function declarations.
An object declaration with constexpr
requires that the declaration has an intializer that is a constant expression so that the compiler always knows the value of the object at compile-time as a constant, but a parameter can't have such an initializer as the parameter is initializer by the caller. So it doesn't have any analogues meaning to constexpr
as top-level specifier on a variable declaration and is therefore not permitted.
There have been proposals to add something like constexpr
function parameters with slightly different meaning, but nothing has been accepted for the standard.
(const
in the template parameter itself is also redundant by the way. When the non-type template parameter is of non-class type, then it is prvalue when used in an expression, which has const
stripped anyway. If it is a class-type, then it is a lvalue that has const
added to it automatically. So there is basically no difference.)