我有不同的 View 类型,每个类型都有一个 std::size_t View::dimension
成员常量,和一个 typename View::value_type
成员(member)类型。
下面的编译类型检查应该验证 From
和 To
是 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_type
或 std::false_type
, 对于任何类型 T
.问题是如果From
或 To
不是 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
和 ::type
。 is_compatible_view_details
只有在 From
和 To
都是 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/