An answer to this question proposed the following method to detect types that are valid for non-type template parameters ("structural types"):
template <auto>
struct nttp_test {};
template<class T>
concept structural = requires { []<T x>(nttp_test<x>) { }; };
I thought a simpler version of this would suffice:
template<class T>
concept structural = requires { []<T>{}; };
However, when trying the following test program
#include <iostream>
template<class T>
concept structural = requires { []<T>{}; };
int main()
{
std::cout << "int: " << structural<int> << '\n';
std::cout << "int*: " << structural<int*> << '\n';
std::cout << "int&: " << structural<int&> << '\n';
std::cout << "int&&: " << structural<int&&> << '\n';
std::cout << "void: " << structural<void> << '\n';
std::cout << "void(): " << structural<void()> << '\n';
std::cout << "void(*)(): " << structural<void(*)()> << '\n';
std::cout << "std::ostream: " << structural<std::ostream> << '\n';
}
in GCC, the output is
int: 1
int*: 1
int&: 1
int&&: 1
void: 1
void(): 1
void(*)(): 1
std::ostream: 1
It appears that, in GCC, every type satisfies the concept. By contrast, clang and MSVC print 0 for int&&, void, and std::ostream. This is also what GCC does if the other, more elaborate method, is used instead.
Is my method correct, or is this a bug in GCC?