4

在 range-v3 中,view_facade类具有begin()功能。

template<typename D = Derived, CONCEPT_REQUIRES_(Same<D, Derived>())>
detail::facade_iterator_t<D> begin()
{
    return {range_access::begin_cursor(derived(), 42)};
}

并且range_access::begin_cursor()是这样实现的,

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()
)

在我的 VS 中,看起来总是调用第二个函数。

我想知道何时将幻数(42)转换为long调用第一个函数。

4

3 回答 3

6

鉴于RANGES_DECLTYPE_AUTO_RETURN 定义为

#define RANGES_DECLTYPE_AUTO_RETURN(...)                        \
    -> decltype(__VA_ARGS__)                                    \
    { return (__VA_ARGS__); }                                   \
    /**/

那么你的两个重载(在宏扩展之后)变成:

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();
}

begin_cursor使用int参数调用时,重载解析会找到一个精确匹配,即第二个重载。最好是long,因为这需要转换参数表达式。但是,如果static_cast<Rng const &>(rng).begin_cursor()无效,即成员函数begin_cursor()不是 const 限定的,则decltype说明符内的表达式将触发替换失败,因此,编译器将继续搜索另一个重载,退回到第一个函数。

于 2016-05-15T14:16:40.770 回答
4
RANGES_DECLTYPE_AUTO_RETURN
(
  static_cast<Rng const &>(rng).begin_cursor()
)

扩展到类似的东西

-> decltype(static_cast<Rng const &>(rng).begin_cursor())
   { return static_cast<Rng const &>(rng).begin_cursor(); }

两者begin_cursor有不同的->decltype返回值,这给了你 SFINAE。两种重载都被考虑。如果版本由于直接上下文中const的表达式格式错误而导致 SFINAE 失败,则将其消除,并选择该版本。decltypelong

如果没有,42宁愿转换为int而不是long. 所以选择了const版本。

于 2016-05-15T14:17:04.447 回答
0

给编译器一个合适的文字?

return {range_access::begin_cursor(derived(), 42l)};

(它是“42 el”,而不是数字 421。:))

于 2016-05-15T13:54:02.350 回答