Consider following type trait:
template<typename T, typename = void>
struct has_begin : std::false_type {};
template<typename T>
struct has_begin<T, std::void_t<
decltype(std::begin(std::declval<std::add_lvalue_reference_t<T>>()))
>> : std::true_type {};
Why does this trait does not consider my user-defined overload for std::begin
?
namespace std {
void begin(foo&) {}
}
int main() {
static_assert(has_begin<foo>::value); // Fails.
foo f;
std::begin(f); // Works.
}
Live example
Interesting observations:
decltype(std::begin(std::add_lva... -> decltype(begin(std::add_lva...
it works if the free function begin
is in the same namespace as foo:
void begin(foo) {
}
but fails for any class outside std:: depending on:
template<class C>
auto begin(C& c) -> decltype(c.begin());
because ADL lookup does not work with templates from other namespaces.
What could I do to support std::begin(foo&)
in my type trait without changing the include order?
Otherwise I have to support both worlds - writing the type trait for std::begin and ADL begin()...
In my functions I already do something like this (suggested here):
auto get_begin() {
using std::begin;
return begin(object);
}
What could I do to support std::begin(foo&) in my type trait without changing the include order?
You don't; std::begin
is not meant to be called directly for arbitrary ranges. If you want to access begin/end
for a range type, you're supposed to use ADL, combined with using std::begin/end
. That's just how the idiom works in C++.
It is illegal to overload methods in the std
namespaces, and std::begin
is no exception. You can create a template specializations of std
-defined templates (based on user-created types), but this is not the proper way to use the C++ idiom.
In C++20, the std::ranges::begin
function is meant to be called directly, and the way you specialize it for a type is through ADL or a member begin
function. So just use the idiom, and everyone will be fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With