[英]“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);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.