The following code issues a warning when compiling with gcc, but only with version <= 9.3
#include <array>
#include <iostream>
template <std::size_t size>
struct A {
using atype = std::array<double, size>;
template <std::size_t index = 0>
static constexpr void fill_array(atype& res)
{
std::get<index>(res) = 1;
if constexpr (index < (size - 1))
fill_array<index + 1>(res);
}
static constexpr atype get_array()
{
atype res;
fill_array(res);
return res;
}
};
int main()
{
auto x = A<3>::get_array();
for (const auto e: x)
std::cout << e << ' ';
}
Test it on godbolt. I am compiling with -Wall -pedantic -std=c++17 -O3
. The issued warning is
In file included from <source>:1:
<source>: In instantiation of 'static constexpr A<size>::atype A<size>::get_array() [with long unsigned int size = 3; A<size>::atype = std::array<double, 3>]':
<source>:26:30: required from here
/opt/compiler-explorer/gcc-9.3.0/include/c++/9.3.0/array:94:12: note: 'using atype = struct std::array<double, 3>' {aka 'struct std::array<double, 3>'} has no user-provided default constructor
94 | struct array
| ^~~~~
/opt/compiler-explorer/gcc-9.3.0/include/c++/9.3.0/array:110:56: note: and the implicitly-defined constructor does not initialize 'double std::array<double, 3>::_M_elems [3]'
110 | typename _AT_Type::_Type _M_elems;
| ^~~~~~~~
Compiler returned: 0
While the std::array
of double is uninitialized, actually the recursive template routine initializes all elements of res
. So, the warning is not "real". In principle, I could "hack" the code by calling fill_array<1>
, thereby skipping the initialization of the 0
component. But code for template functions is generated only when instantiated with given template parameters, so again, in the above code the compiler never skips to generate fill_array<0>
.
Stragely, this warning only appears up to version 9.3 of gcc. Also, clang does not issue the warning. Even more strangely, when the functions are not embedded into a class, the warning disappear. With the following code:
#include <array>
#include <iostream>
constexpr std::size_t size = 3;
using atype = std::array<double, size>;
template <std::size_t index = 0>
void fill_array(atype& res)
{
std::get<index>(res) = 1;
if constexpr (index < (size - 1))
fill_array<index + 1>(res);
}
atype get_array()
{
atype res;
fill_array(res);
return res;
}
int main()
{
auto x = get_array();
for (const auto e: x)
std::cout << e << ' ';
}
no warning are displayed, despite being apparently identical to the first code. Test it here.
Is there a reason for the different compiler behavior between the two codes?
Can I suppress the warning only for this variable, without introducing an overhead?