In my world, a StrictNodeType
should be anything that defines the types PredContainer
and SuccContainer
, so I wrote
template<typename N>
concept StrictNodeType = requires {
typename N::PredContainer;
typename N::SuccContainer;
};
However, GCC-11.2 gives me the following error:
error: satisfaction of atomic constraint 'requires{typename N::PredContainer;typename N::SuccContainer;} [with N = typename std::remove_cvref<_Tp>::type::Node]' depends on itself
164 | concept StrictNodeType = requires {
| ^~~~~~~~~~
165 | typename N::PredContainer;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
166 | typename N::SuccContainer;something;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
167 | };
How is that possible? Why can't GCC simply inspect the given type and check if it provides the requested subtypes?
Here's a minimum breaking example:
#include <type_traits>
template<typename N>
concept StrictNodeType = requires {
typename N::something;
};
template<StrictNodeType N> using Int = int;
template<int>
struct X {using type = Int<X>; };
using ThisBreaks = Int<X<0>>;
It seems there is an infinite recursion issue that constrains a concept more than it would be without it. I made a few changes to get more directly at the issue:
#include <type_traits>
template<typename N>
concept StrictNodeType = requires {
typename N::something;
};
#if 1
template<StrictNodeType N> using Int = int;
#else
template<typename N> using Int = int;
#endif
template<int>
struct X { using something = Int<X<0>>; };
using ThisBreaks=Int<X<0>>;
ThisBreaks foo()
{
return ThisBreaks{};
}
This yields the following error:
<source>:15:37: error: template constraint failure for 'template<class N> requires StrictNodeType<N> using Int = int'
15 | struct X { using something = Int<X<0>>; };
| ^~
<source>:15:37: note: constraints not satisfied
<source>: In substitution of 'template<class N> requires StrictNodeType<N> using Int = int [with N = X<0>]':
<source>:15:37: required from here
<source>:4:9: required for the satisfaction of 'StrictNodeType<N>' [with N = X<0>]
<source>:4:26: in requirements [with N = X<0>]
<source>:5:14: note: the required type 'typename N::something' is invalid
5 | typename N::something;
| ~~~~~~~~~^~~~~~~~~~~~~
cc1plus: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
<source>:17:25: error: template constraint failure for 'template<class N> requires StrictNodeType<N> using Int = int'
17 | using ThisBreaks=Int<X<0>>;
| ^~
<source>:17:25: note: constraints not satisfied
<source>: In substitution of 'template<class N> requires StrictNodeType<N> using Int = int [with N = X<0>]':
<source>:17:25: required from here
<source>:4:9: required for the satisfaction of 'StrictNodeType<N>' [with N = X<0>]
<source>:4:26: in requirements [with N = X<0>]
<source>:5:14: note: the required type 'typename N::something' is invalid
5 | typename N::something;
| ~~~~~~~~~^~~~~~~~~~~~~
<source>:19:1: error: 'ThisBreaks' does not name a type
19 | ThisBreaks foo()
| ^~~~~~~~~~
Compiler returned: 1
Changing #if 1
to #if 0
compiles fine, only the Concept objects to the infinite recursion.
(Play with it here: https://godbolt.org/z/56Yd7W3sf )