Search code examples
c++templatesc++17constantsconstexpr

Why is constexpr not interchangeable with const in this instance?


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?


Solution

  • 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.)