In my C++ JSON library, I recently had a regression with GCC7. I stripped down the affected code and hope to understand the error.
The code
Consider this header myclass.hpp
:
#pragma once
template <typename X>
struct A
{
struct value_t
{
X array;
};
static A array()
{
return A();
}
friend bool operator<(const A& lhs, const A& rhs) noexcept
{
return lhs.val.array < rhs.val.array;
}
value_t val = {};
};
As you see, I used the name "array" as member variable name in struct value_t
, as name of a static function. I then included the header in the following file:
#include <array>
using std::array; // note this!
#include "myclass.hpp"
int main()
{}
The problem
The code compiles with GCC6 and Clang5 (using -std=c++11
), but GCC7 reports:
In file included from example.cpp:3:0:
myclass.hpp: In function 'bool operator<(const A<X>&, const A<X>&)':
myclass.hpp:19:40: error: wrong number of template arguments (1, should be 2)
return lhs.val.array < rhs.val.array;
^~~~~
In file included from example.cpp:1:0:
/usr/local/Cellar/gcc/7.1.0/include/c++/7.1.0/array:94:12: note: provided for 'template<class _Tp, long unsigned int _Nm> struct std::array'
struct array
^~~~~
make: *** [all] Error 1
It seems as if the parser reads the "array" in lhs.val.array
as std::array
and treats the following <
as the start of a template list.
The code can be compiled if I make any of the changes below:
- Remove the
using std::array;
or move it behind#include "myclass.hpp"
. - Change
return lhs.val.array < rhs.val.array;
toreturn (lhs.val.array) < rhs.val.array;
.
In addition, either compiler fails if I remove the static A array()
function...
My questions
- Is the code correct in the first place? Am I allowed to use "array" as a name even if I use
using std::array;
? - If the code is correct, is this a bug in GCC7?