Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constexpr member function with std::vector data member in C++

Tags:

I am trying to implement in a C++ class a constexpr member function which returns a template parameter. The code is supposed to be c++11 compatible. However I encounter compilation issues when the templated class also contains STL containers as data members such as std::vector (which are untouched by the constexpr member function).

A minimal example is given by the following code:

 #include <vector> #include <iostream> #include <array>   template<size_t n> struct A  {    constexpr size_t dimensions() const   {     return n;   } private:   std::vector<double> a; };   int main(int argc,char ** argv) {   auto a=A<3>();   std::array<double,a.dimensions()> arr;  } 

The code compiles correctly with the commands

g++ -std=c++14 -O3 quickTest.cpp -o test -Wall

clang++ -std=c++11 -O3 quickTest.cpp -o test -Wall

but fails when I use

g++ -std=c++11 -O3 quickTest.cpp -o test -Wall

with the error

quickTest.cpp:22:33: error: call to non-‘constexpr’ function ‘size_t A<n>::dimensions() const [with long unsigned int n = 3; size_t = long unsigned int]’    std::array<double,a.dimensions()> arr;                      ~~~~~~~~~~~~^~ quickTest.cpp:10:20: note: ‘size_t A<n>::dimensions() const [with long unsigned int n = 3; size_t = long unsigned int]’ is not usable as a ‘constexpr’ function because:    constexpr size_t dimensions() const                     ^~~~~~~~~~ quickTest.cpp:22:33: error: call to non-‘constexpr’ function ‘size_t A<n>::dimensions() const [with long unsigned int n = 3; size_t = long unsigned int]’    std::array<double,a.dimensions()> arr;                      ~~~~~~~~~~~~^~ quickTest.cpp:22:33: note: in template argument for type ‘long unsigned int’ 

Why does the code not compile with gcc -std=c++11 but does compile with clang++ -std=c++11 ? How could one make this code snippet work with older versions of gcc which many not support c++14/17, but only c++11 ?

I am using gcc 8.1.1 and clang 6.0.1

like image 769
Luca Parisi Avatar asked Apr 26 '19 11:04

Luca Parisi


People also ask

Can a member function be constexpr?

const can only be used with non-static member functions whereas constexpr can be used with member and non-member functions, even with constructors but with condition that argument and return type must be of literal types.

Does C have constexpr?

No, no such thing exists in C.

Is Vector a constexpr?

Formally, that's because vector constructor is not declared constexpr .

Is STD string a constexpr?

However, std::string objects generally cannot be constexpr, because any dynamically allocated storage must be released in the same evaluation of constant expression.


1 Answers

C++11 had a rule [dcl.constexpr]/8:

... The class of which that function is a member shall be a literal type ([basic.types]).

struct A is not a literal type because of the vector, hence its non-static member functions cannot be constexpr.

So GCC is right to reject the code in C++11 mode.

C++14 removed that restriction.

The solution for C++11 is to declare dimensions() static:

  static constexpr size_t dimensions()   {     return n;   } 

Live demo

like image 143
rustyx Avatar answered Sep 20 '22 14:09

rustyx