Ad

C++ Template Specialization Changes Constexpr Rules?

- 1 answer

I am using g++ (GCC) 11.2.0.

The following piece of code

#include <vector>
#include <iostream>

template<int size>
constexpr std::vector<int> get_vector() {
        return std::vector<int> (size);
}

int main() {
        std::cout << get_vector<5>().size() << std::endl;
}

compiles successfully and outputs 5 when executed. Just as I expected.

However, if I add specialization

#include <vector>
#include <iostream>

template<int size>
constexpr std::vector<int> get_vector() {
        return std::vector<int> (size);
}

template<>
constexpr std::vector<int> get_vector<2>() {
        return std::vector<int> (2);
}

int main() {
        std::cout << get_vector<5>().size() << std::endl;
}

it fails to compile and produces the error

another.cpp: In function ‘constexpr std::vector<int> get_vector() [with int size = 2]’:
another.cpp:10:28: error: invalid return type ‘std::vector<int>’ of ‘constexpr’ function ‘constexpr std::vector<int> get_vector() [with int size = 2]’
   10 | constexpr std::vector<int> get_vector<2>() {
      |                            ^~~~~~~~~~~~~
In file included from /usr/include/c++/11.2.0/vector:67,
                 from another.cpp:1:
/usr/include/c++/11.2.0/bits/stl_vector.h:389:11: note: ‘std::vector<int>’ is not literal because:
  389 |     class vector : protected _Vector_base<_Tp, _Alloc>
      |           ^~~~~~
/usr/include/c++/11.2.0/bits/stl_vector.h:389:11: note:   ‘std::vector<int>’ has a non-trivial destructor

Why does it happen?

Ad

Answer

If you take a look at compiler support you will find out that gcc supports constexpr std::vector from version 12. As you tell us you use gcc 11.2 it simply is not implemented in the library.

You can see it working as expected on godbolt with trunk versions of gcc and clang. For gcc it will be part of gcc 12.x versions.

Ad
source: stackoverflow.com
Ad