c++ - SFINAE 在 std::enable_if 参数中

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

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

下面的编译类型检查应该验证 FromTo是 View (使用 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<T>是这样的,它总是评估为 std::true_typestd::false_type , 对于任何类型 T .问题是如果FromTo不是 View 类型,则 From::dimension (例如)可能不存在,并且 is_compatible_view<From, To>导致编译错误。 它应该评估为 std::false_type在这种情况下。

is_compatible_view用于 SFINAE 与 std::enable_if , 禁用成员函数。例如一个 View 类可以有一个成员函数

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不是 View ,并在 is_compatible_view<Not_a_view, ...> 中导致编译错误.调用view.assign_from(Not_a_view())时, SFINAE 不适用,而是在编译器尝试解析第一个 assign_from 时发生编译错误功能。

如何is_compatible_view写成这样可以正常工作吗?在 C++17 中做 std::conjunction<...>允许这样做吗?

最佳答案

一种方法是使用类似 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 都是 View 时才会被实例化。


类似的方法是将 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

关于c++ - SFINAE 在 std::enable_if 参数中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41509018/

相关文章:

python - 我的 Py_NoneStruct 符号(python、boost.python)在哪里?

C++:在第一个 cin.ignore 之后忽略输入

c++ - 使用 malloc() 和 free() 实现一个简单的分配器类

c++ - g++ std::is_function 实现:_ArgTypes 后跟 6 个句点是什么意思?

c++ - 具有特征参数的模板特化函数

c++ - Clang 与 GCC : Error in unevaluated context breaks SFINAE

c++ - 为什么在这种情况下重载决议不明确?

c++ - 更新 : C++ undefined reference

c++ - 如何防止在 for_each 的末尾调用复制构造函数?

c++ - 如何使用 SFINAE 来防止模板函数变窄?