【问题标题】:CONCEPT_REQUIRES_ implementation in ranges-v3范围-v3 中的 CONCEPT_REQUIRES_ 实现
【发布时间】:2017-08-25 18:19:36
【问题描述】:

尝试学习如何使用 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 模板参数?

【问题讨论】:

    标签: c++ template-meta-programming range-v3


    【解决方案1】:

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

    关闭。它实际上翻译为:

    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&lt;T&gt;() 不依赖于此函数模板的参数,编译器将诊断出std::enable_if_t&lt;ranges::Integral&lt;T&gt;()&gt; - 降低为typename std::enable_if&lt;ranges::Integral&lt;T&gt;()&gt;::type - 格式错误,因为std::enable_if&lt;false&gt; 不包含名为type 的成员.随着 injection-unique-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

    【讨论】:

    • 所以,在没有注入int的情况下,我理解如果用户实例化S,编译器会发出错误,即使函数f没有被调用,因此没有实例化?
    • 来自static-assert-dependent-on-non-type-template-parameter,它甚至更加微妙“来自[temp.res]/8:如果无法为模板生成有效的特化,并且该模板未实例化,模板格式不正确,不需要诊断。”。所以我们应该有可能的有效实例化(这可以通过为魔法参数提供43 来实现)。 std::enable_if_t&lt;(some_unique_name == some_unique_name + 1) || (__VA_ARGS__)&gt; 是错误的。
    • 你不只是喜欢模板元编程吗?在这里,我添加了一个额外的模板参数typename T_ = T 并在T_ 上进行了测试。甚至没想到这是有效的。
    猜你喜欢
    • 2021-03-07
    • 2020-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多