Najprostszą sztuczką jest poleganie na rozdzielczości przeciążenia, która już określa jej zasady pierwszeństwa. W poniższym rozwiązaniu, z dodatkowym argumentem, jest on lepszy niż 0 -> char
, a zatem ten pierwszy będzie preferowany, jeśli nie zostanie wykluczony przez wyrażenie SFINAE, a drugi będzie nadal zdolny do wywołania zastępczego.
#include <utility>
template <typename T, typename U>
auto smart_division_impl(T a, U b, int) -> decltype(a/b)
{
return a/b;
}
template <typename T, typename U>
auto smart_division_impl(T a, U b, char) -> decltype(a * (U(1)/b))
{
return a * (U(1)/b);
}
template <typename T, typename U>
auto smart_division(T&& a, U&& b) -> decltype(smart_division_impl(std::forward<T>(a), std::forward<U>(b), 0))
{
return smart_division_impl(std::forward<T>(a), std::forward<U>(b), 0);
}
DEMO
Jeśli miał więcej przeciążeń, można zamiast wprowadzać typ pomocnika priorytet każdego z nich: znowu
template <int I> struct rank : rank<I-1> {};
template <> struct rank<0> {};
template <typename T, typename U>
auto smart_division_impl(T a, U b, rank<2>) -> decltype(a/b)
// ~~~~~~^ highest priority
{
return a/b;
}
template <typename T, typename U>
auto smart_division_impl(T a, U b, rank<1>) -> decltype(a * (U(1)/b))
// ~~~~~~^ mid priority
{
return a * (U(1)/b);
}
template <typename T, typename U>
int smart_division_impl(T a, U b, rank<0>)
// ~~~~~~^ lowest priority
{
return 0;
}
template <typename T, typename U>
auto smart_division(T&& a, U&& b) -> decltype(smart_division_impl(std::forward<T>(a), std::forward<U>(b), rank<2>{}))
{
return smart_division_impl(std::forward<T>(a), std::forward<U>(b), rank<2>{});
}
DEMO 2
Tutaj rank<2> -> rank<2>
jest lepsza niż rank<2> -> rank<1>
który z kolei jest preferowany do rank<2> -> rank<0>
Dobrze, co próbowaliście? – edmz