短路运算符在enable_if

Short Circuiting Operators in an enable_if

本文关键字:if enable 运算符 短路      更新时间:2023-10-16

我想编写一个需要array<int, 3>int[3]的模板化函数。我试图在enable_if中捕捉到这一点:

template<typename T>
enable_if_t<is_array_v<T> && extent_v<T> == 3U || !is_array_v<T> && tuple_size<T>::value == 3U> foo(const T& param) {}

不幸的是,对于int[3]tupple_size没有定义,这导致模板在评估短路之前无法编译。

我也尝试使用conditional来执行此操作,但这具有相同的问题,即在考虑条件之前确保两个选项都对T有效。

我知道我可以通过专业化来做到这一点。但是代码在函数主体中完全相同。我讨厌在实现相同时我专门从事的事实。

有没有办法在评估条件之前强制短路?

利用非数组类型的extent<T>为零,因此是伪造的,并且disjunction从列表中的第一个真实类型派生出短路:

template<typename T>
enable_if_t<disjunction<extent<T>, tuple_size<T>>::value == 3U> foo(const T& param) {}

这可能太聪明了。请注意,您不能在此处使用disjunction_v


conditional也应该工作得很好。诀窍是在选择正确的类型之前不要要求::value

template<typename T>
enable_if_t<conditional_t<is_array_v<T>, extent<T>, tuple_size<T>>::value == 3U> 
foo(const T& param) {}

简而言之,不,模板替换必须始终有效。只定义一个特定的模板来匹配数组可能会更容易:

template <typename T>
struct IsArrayInt3 { enum: bool { value = false }; };
template <>
struct IsArrayInt3<int[3]> { enum: bool { value = true }; };
template <>
struct IsArrayInt3<std::array<int, 3>> { enum: bool { value = true }; };

我会建议另一种方法:2 个重载(总是更喜欢重载而不是模板专用化(,调用包含通用代码的公共函数:

namespace detail
{
template <class T>
auto foo_impl(const T& a)
{
// common code
}
}
template <class T>
auto foo(const std::array<T, 3>& a)
{
detail::foo_impl(a);
}
template <class T>
auto foo(const T(&a)[3])
{
detail::foo_impl(a);
}

这清晰、轻松,并避免了代码重复。

另一种方法是创建自己的特征:

template <class T, std::size_t Size>
struct my_is_array : std::false_type
{};
template <class T, std::size_t Size>
struct my_is_array<std::array<T, Size>, Size> : std::true_type
{};
template <class T, std::size_t Size>
struct my_is_array<T[Size], Size> : std::true_type
{};
template<typename T>
std::enable_if_t<my_is_array<T, 3>::value> foo(const T& param) {}

或者(我实际上更喜欢这个(:

template <class T>
struct array_size_or_zero : std::integral_constant<std::size_t, 0>
{};
template <class T, std::size_t Size>
struct array_size_or_zero<std::array<T, Size>> : std::integral_constant<std::size_t, Size>
{};
template <class T, std::size_t Size>
struct array_size_or_zero<T[Size]> : std::integral_constant<std::size_t, Size>
{};
template<typename T>
std::enable_if_t<array_size_or_zero<T>::value == 3> foo(const T& param) {}

小心!!:foo必须通过引用具有参数,否则数组将衰减为指针。