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
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.
No, no such thing exists in C.
Formally, that's because vector constructor is not declared constexpr .
However, std::string objects generally cannot be constexpr, because any dynamically allocated storage must be released in the same evaluation of constant expression.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With