I am wondering how the std::same_as is defined and how we use it in a concept or requirement.
Example:
void f1() { }
bool f2() { return true; }
template < typename T>
void Do( T func )
{
if constexpr ( requires { { func() } -> std::same_as<bool>; } )
{
std::cout << "Func returns bool " << std::endl;
}
if constexpr ( requires { { func() } -> std::same_as<void>; } )
{
std::cout << "Func returns void " << std::endl;
}
}
int main()
{
Do( f1 );
Do( f2 );
}
That works as expected.
But if I look on the definition of std::same_as I find a possible implementation:
namespace detail {
template< class T, class U >
concept SameHelper = std::is_same_v<T, U>;
}
template< class T, class U >
concept same_as = detail::SameHelper<T, U> && detail::SameHelper<U, T>;
And what makes me wonder is that I see two template parms T and U in that case while we only need to write one like { { func() } -> std::same_as<bool>; }.
Is it some kind of magic that a { { func() } -> std::same_as<bool>; } will be converted to std::same_as<magic_return_type, bool> in that case?
CodePudding user response:
A concept is generally similar to a constexpr inline bool variable template. However, it does have special properties. With regard to this question, a concept whose first template parameter is a type is a special kind of concept: a "type concept".
In certain locations, a type concept can be used without its first template parameter. In those places, the first parameter will be deduced based on how it gets used.
In compound requirements of a requires expression, a type concept is what follows the ->. The first parameter of the concept will be filled in by the type of the expression E in the {}, as if by decltype((E)).
