Is this a correct method of detecting structural types?

Viewed 80

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?

0 Answers
Related