I would like to define a member function in a class template only if traits contain type and use type as its argument like that:
struct A {};
struct B { using type = int; };
template <typename T>
concept has_type = requires { typename T::type; };
template <typename Traits>
struct Handler
{
void set(typename Traits::type)
requires has_type<Traits>
{}
};
Unfortunately, typename Traits::type is parsed before the requires clause and it fails to compile if type does not exist (struct A):
<source>:19:14: error: no type named 'type' in 'struct A'
19 | void set(typename Traits::type)
I could only come up with this alternative, which looks excessively cumbersome:
template <typename Traits>
struct Handler
{
template <typename Type>
requires has_type<Traits> && std::same_as<Type, typename Traits::type>
void set(Type)
{}
};
It also fails to compile under clang (although I expected it to short-circuit), but gcc compiles it correctly:
<source>:20:78: error: no type named 'type' in 'A'
requires has_type<Traits> && std::same_as<Type, typename Traits::type>
Questions
- What is the idiomatic way to define
setdepending on whetherTraitsclass containstype? - Why does clang try to evaluate
std::same_asifrequires has_typefailed? - Who is right, clang or gcc?