In range-v3, view_facade
class has begin()
function.
template<typename D = Derived, CONCEPT_REQUIRES_(Same<D, Derived>())>
detail::facade_iterator_t<D> begin()
{
return {range_access::begin_cursor(derived(), 42)};
}
And the range_access::begin_cursor()
is implemented like this,
template<typename Rng>
static RANGES_CXX14_CONSTEXPR auto begin_cursor(Rng & rng, long) // --1
RANGES_DECLTYPE_AUTO_RETURN
(
rng.begin_cursor()
)
template<typename Rng>
static RANGES_CXX14_CONSTEXPR auto begin_cursor(Rng & rng, int) // --2
RANGES_DECLTYPE_AUTO_RETURN
(
static_cast<Rng const &>(rng).begin_cursor()
)
In my VS, it looks the second function is always called.
I wonder when the magic number (42) is converted into long
to call first function.
Given that RANGES_DECLTYPE_AUTO_RETURN
is defined as:
#define RANGES_DECLTYPE_AUTO_RETURN(...) \
-> decltype(__VA_ARGS__) \
{ return (__VA_ARGS__); } \
/**/
then your two overloads (after macro expansion) become:
template<typename Rng>
static auto begin_cursor(Rng & rng, long) // --1
-> decltype(rng.begin_cursor())
{
return rng.begin_cursor()
}
template<typename Rng>
static auto begin_cursor(Rng & rng, int) // --2
-> decltype(static_cast<Rng const &>(rng).begin_cursor())
{
return static_cast<Rng const &>(rng).begin_cursor();
}
When calling begin_cursor
with an int
argument, overload resolution finds an exact match which is the second overload. It is preferred to long
, as this one requires a conversion of the argument expression. However, if static_cast<Rng const &>(rng).begin_cursor()
is invalid, i.e., when member function begin_cursor()
is not const-qualified, the expression inside the decltype
specifier will trigger a substitution failure, therefore, the compiler will continue to search for another overload, falling back to the first function.
RANGES_DECLTYPE_AUTO_RETURN
(
static_cast<Rng const &>(rng).begin_cursor()
)
expands to something like
-> decltype(static_cast<Rng const &>(rng).begin_cursor())
{ return static_cast<Rng const &>(rng).begin_cursor(); }
the two begin_cursor
have different ->decltype
return values, which gives you SFINAE. Both overloads are considered. If the const
version has a SFINAE failure due to the decltype
expression being ill-formed in the immediate context, it is eliminated, and the long
version is picked.
If it does not, 42
prefers to convert to int
instead of long
. So the const
version is picked.
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