template<unsigned N, enable_if_t<is_multiple_of<N, 3>>...>
void print_fizzbuzz(){ std::cout << "fizz\n"; }
template<unsigned N, enable_if_t<is_multiple_of<N, 5>>...>
void print_fizzbuzz(){ std::cout << "buzz\n"; }
template<unsigned N, enable_if_t<is_multiple_of<N, 15>>...> // this is ambiguous
void print_fizzbuzz(){ std::cout << "fizzbuzz\n"; }
By using derived-to-base conversions we can create a total ordering for selecting SFINAE overloads.
That is, we resolve ambiguity by using the following inheritance hierarchy:
template<unsigned I> struct choice : choice<I+1>{};
choice<0> has a higher ordering than choice<1>, and we can therefore use choice<0> as a function parameter to make is_multiple_of<N, 15> a better overload, thereby resolving the ambiguity.
The complete fizzbuzz example:
#include <type_traits>
#include <iostream>template<class C, class T = int>
using enable_if_t = typename std::enable_if<C::value, T>::type;
template<int N, int M>
struct is_multiple_of : std::integral_constant<bool, N % M == 0>{};
//-------------------------------
template<unsigned I> struct choice : choice<I+1>{};
template<> struct choice<10>{}; // suitably high terminating condition
struct otherwise{ otherwise(...){} };
struct select_overload : choice<0>{};
//-------------------------------
template<unsigned N, enable_if_t< is_multiple_of<N, 15> >...>
void print_fizzbuzz(choice<0>) { std::cout << "fizzbuzz\n"; }
template<unsigned N, enable_if_t< is_multiple_of<N, 3> >...>
void print_fizzbuzz(choice<1>) { std::cout << "fizz\n"; }
template<unsigned N, enable_if_t< is_multiple_of<N, 5> >...>
void print_fizzbuzz(choice<2>) { std::cout << "buzz\n"; }
template<unsigned N>
void print_fizzbuzz(otherwise){ std::cout << N << "\n"; }
template<unsigned N = 1>
void do_fizzbuzz()
{
print_fizzbuzz<N>(select_overload{});
do_fizzbuzz<N+1>();
}
template<>
void do_fizzbuzz<50>()
{
print_fizzbuzz<50>(select_overload{});
}
//-------------------------------
int main()
{
do_fizzbuzz();
}
This excellent technique by Xeo, as described here
No comments:
Post a Comment