【问题标题】:SFINAE inside std::enable_if argumentstd::enable_if 参数中的 SFINAE
【发布时间】:2017-01-06 15:39:53
【问题描述】:

我有不同的view 类型,每个类型都有一个std::size_t View::dimension 成员常量和一个typename View::value_type 成员类型。

下面的编译类型检查应该验证FromTo是否都是视图(使用is_view<>验证),并且From的内容可以分配给To。 (相同的尺寸和可转换的值类型)。

template<typename From, typename To>
struct is_compatible_view : std::integral_constant<bool,
    is_view<From>::value &&
    is_view<To>::value &&
    From::dimension == To::dimension &&
    std::is_convertible<typename From::value_type, typename To::value_type>::value
> { };

is_view&lt;T&gt; 对于任何类型的T,总是计算为std::true_typestd::false_type。问题是如果FromTo不是视图类型,那么From::dimension(例如)可能不存在,is_compatible_view&lt;From, To&gt;会导致编译错误。 在这种情况下,它应该改为std::false_type

is_compatible_view 用于带有std::enable_if 的 SFINAE,以禁用成员函数。例如一个视图类可以有一个成员函数

struct View {
    constexpr static std::size_t dimension = ...
    using value_type = ...

    template<typename Other_view>
    std::enable_if_t<is_compatible_view<Other_view, View>> assign_from(const Other_view&);

    void assign_from(const Not_a_view&);
};

Not_a_view 不是视图,会导致is_compatible_view&lt;Not_a_view, ...&gt; 出现编译错误。调用view.assign_from(Not_a_view()) 时,SFINAE 不适用,而是在编译器尝试解析第一个assign_from 函数时出现编译错误。

如何编写is_compatible_view 以使其正常工作?在 C++17 中,std::conjunction&lt;...&gt; 是否允许这样做?

【问题讨论】:

    标签: c++ c++11 sfinae c++17 enable-if


    【解决方案1】:

    一种方法是使用 std::conditional 之类的东西来延迟评估您的类型特征的某些部分,直到我们验证您的类型特征的其他部分已经正确为止。

    即:

    // this one is only valid if From and To are views
    template <class From, class To>
    struct is_compatible_view_details : std::integral_constant<bool,
        From::dimension == To::dimension &&
        std::is_convertible<typename From::value_type, typename To::value_type>::value
    > { };        
    
    // this is the top level one
    template<typename From, typename To>
    struct is_compatible_view : std::conditional_t<
        is_view<From>::value && is_view<To>::value,
        is_compatible_view_details<From, To>,
        std::false_type>::type
    { };
    

    请注意,我同时使用了conditional_t::typeis_compatible_view_details 只有在 FromTo 都是视图时才会被实例化。


    类似的方法是将std::conjunction 与上述方法一起使用,因为短路同样会延迟评估:

    template <class From, class To>
    struct is_compatible_view : std::conjunction_t<
        is_view<From>,
        is_view<To>,
        is_compatible_view_details<From, To>
        >
    { };
    

    无论哪种方式,您都需要提取细节。


    第三种方法是使用enable_if_t 作为特化:

    template <class From, class To, class = void>
    struct is_compatible_view : std::false_type { };
    
    template <class From, class To>
    struct is_compatible_view<From, To, std::enable_if_t<
        is_view<From>::value &&
        is_view<To>::value &&
        From::dimension == To::dimension &&
        std::is_convertible<typename From::value_type, typename To::value_type>::value>>
    : std::true_type { };
    

    这里,如果enable_if_t 中的任何表达式格式不正确,SFINAE 就会启动,我们只使用主模板,即false_type

    【讨论】:

    • 我实际上并没有真正看到您的第一个 sn-p 中的 ::type 的意义。此外,根据用例,创建一个 enable_if_compatible_view 别名模板可能就足够了,它将 From::value_type 等中的任何错误拉入直接上下文中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-29
    • 2012-08-23
    • 1970-01-01
    • 2012-06-18
    • 1970-01-01
    相关资源
    最近更新 更多