I would like to write a concept that would allow me to verify if a given statement, using ADL, is valid and has a proper return type.
In my specific case, I want to write a String
concept that should enforce the following requirements:
The type has begin
and end
semantics for both its const
and non-const
flavors:
// Akin to what this function does for `T` and `T const`
template< typename T >
auto test(T& t) {
using std::begin;
return begin(t);
}
// calling test with `T` and `T const` should be valid.
The return types of begin
and end
are consistent for both const
and non-const
flavors and they satisfy the std::contiguous_iterator
concept.
So far I went with a trait implementation like the following:
namespace Adl {
using std::begin;
template< typename T >
using HasBeginT = decltype(begin(std::declval< T >()));
}
template< typename T >
using HasBegin = std::experimental::is_detected< Adl::HasBeginT, T >;
But I would like to directly embed this ADL usage in the definition of my constraint instead.
The idiom using std::X; X(...);
is considered a bad idea post-C++20. The standard idiom now is to create a customization point object for X
. Or in your case, use the existing customization point object: std::ranges::begin
.
The way you call such a customization point is by spelling it out in full; internally, it can make an ADL call (without using
anything) if the type being provided has such a call.