5

尝试学习如何使用 Eric Niebler 的 range-v3 库,并阅读源代码,我看到了宏定义:

#define CONCEPT_PP_CAT_(X, Y) X ## Y
#define CONCEPT_PP_CAT(X, Y)  CONCEPT_PP_CAT_(X, Y)

/// \addtogroup group-concepts                                                                                                                                                                  
/// @{                                                                                                                                                                                          
#define CONCEPT_REQUIRES_(...)                                                      \
    int CONCEPT_PP_CAT(_concept_requires_, __LINE__) = 42,                          \
    typename std::enable_if<                                                        \
        (CONCEPT_PP_CAT(_concept_requires_, __LINE__) == 43) || (__VA_ARGS__),      \
        int                                                                         \
    >::type = 0                                                                     \
    /**/

因此,简而言之,模板定义如下:

template<typename I, typename O,
    CONCEPT_REQUIRES_(InputIterator<I>() &&
                      WeaklyIncrementable<O>())>
void fun_signature() {}

被翻译为:

template<typename I, typename O,
         int a_unique_name = 42,
         typename std::enable_if
           <false || (InputIterator<I>() &&
                      WeaklyIncrementable<O>()), int>::type = 0
        >
void fun_signature() {}

我想知道为什么那个宏是这样实现的。为什么需要这个整数,为什么它需要一个false || cond而不只是一个cond模板参数?

4

1 回答 1

6

像...这样的模板定义被翻译为...

关闭。它实际上翻译为:

template<typename I, typename O,
         int a_unique_name = 42,
         typename std::enable_if
           <a_unique_name == 43 || (InputIterator<I>() &&
                      WeaklyIncrementable<O>()), int>::type = 0
        >
void fun_signature() {}

唯一命名int是为了确保条件enable_if依赖于模板参数,以避免在模板定义时而不是在实例化时检查条件,以便 SFINAE 可以发生。考虑这个类定义:

template<class T>
struct S {
    template<class U, CONCEPT_REQUIRES_(ranges::Integral<T>())>
    void f(U);
};

如果没有注入唯一- int,此定义将降低为:

template<class T>
struct S {
    template<class U, std::enable_if_t<ranges::Integral<T>()>>
    void f(U);
};

并且由于ranges::Integral<T>()不依赖于此函数模板的参数,编译器将诊断出std::enable_if_t<ranges::Integral<T>()>- 降低到typename std::enable_if<ranges::Integral<T>()>::type- 是格式错误的,因为std::enable_if<false>不包含名为 的成员type。使用注入的唯一- int,类定义降低为:

template<class T>
struct S {
    template<class U, int some_unique_name = 42,
        std::enable_if_t<some_unique_name == 43 || ranges::Integral<T>()>>
    void f(U);
};

现在编译器无法enable_if_t在模板定义时执行任何分析,因为some_unique_name模板参数可能43由用户指定。

于 2017-08-25T18:48:21.593 回答