簡體   English   中英

“Inverse SFINAE” 避免模棱兩可的過載

[英]“Inverse SFINAE” to avoid ambiguous overload

如果第二個模板實例化,如何防止下面的第一個模板實例化? (即如果static_cast<T>(0)T::zero()都被定義了)

template<typename T>
auto zero() ->decltype(static_cast<T>(0)) {
    return static_cast<T>(0);
}

template<typename T>
auto zero() ->decltype(T::zero()) {
    return T::zero();
}

如果您需要通過細粒度控制重載等級將其擴展到多個重載,常用的技術是使用標簽調度。

template<int r>
struct rank : rank<r - 1> {};

template<>
struct rank<0> {};

template<typename T>
auto zero_impl(rank<0>) -> decltype(static_cast<T>(0)) {
    return static_cast<T>(0);
}

template<typename T>
auto zero_impl(rank<1>) ->decltype(T::zero()) {
    return T::zero();
}

template<typename T>
auto zero() { return zero_impl<T>(rank<10>{}); }

派生到基類轉換將更喜歡最接近的基類。 這意味着調用最高等級的重載。 因為在編譯器的眼中,那將具有最好的隱式轉換序列。

沒有enable_if ,依賴於整數轉換等級的內置規則( 0 -> int轉換優於0 -> char ,這使得前者成為首選候選,而后者成為可行的第二選擇候選):

template <typename T>
auto zero_helper(char) -> decltype(static_cast<T>(0))
{
    return static_cast<T>(0);
}

template <typename T>
auto zero_helper(int) -> decltype(T::zero())
{
    return T::zero();
}

template <typename T>
auto zero() -> decltype(auto)
{
    return zero_helper<T>(0);
}

演示

使用您自己的enable_if謂詞(類似於std::void_t技術):

#include <type_traits>

template <typename...>
struct voider { using type = void; };

template <typename... Ts>
using void_t = typename voider<Ts...>::type;

template <typename T, typename = void_t<>>
struct has_zero : std::false_type {};

template <typename T>
struct has_zero<T, void_t<decltype(T::zero())>> : std::true_type {};

template <typename T>
auto zero()
    -> typename std::enable_if<has_zero<T>::value, decltype(T::zero())>::type
{
    return T::zero();
}

template <typename T>
auto zero()
    -> typename std::enable_if<!has_zero<T>::value, T>::type
{
    return static_cast<T>(0);
}

演示 2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM