Il trucco più semplice è affidarsi alla risoluzione di sovraccarico che già definisce le sue regole di precedenza. Nella soluzione seguente, con un argomento aggiuntivo 0
, 0 -> int
è migliore di 0 -> char
, quindi, il primo sarà il preferito se non escluso da un'espressione SFINAE e quest'ultimo è ancora utilizzabile per una chiamata di fallback.
#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
Se tu avessi più sovraccarichi, si potrebbe invece introdurre un tipo di supporto per dare la priorità ciascuno:
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
Anche in questo caso, rank<2> -> rank<2>
è meglio di rank<2> -> rank<1>
che a sua volta è preferito a rank<2> -> rank<0>
Ok, che hai provato? – edmz