具有大量选项的重载分辨率
如果你需要在几个选项之间进行选择,只需通过 enable_if<>
启用一个选项可能非常繁琐,因为有几个条件也需要被否定。
可以使用继承(即标签分派)来选择重载之间的顺序。
我们不是测试需要格式良好的东西,也测试所有其他版本条件的否定,而是测试我们需要的东西,最好是在尾随回报中的 decltype
。
这可能会留下很好的选择,我们区分那些使用’标签’,类似于迭代器 - 特征标签(random_access_tag
等)。这是有效的,因为直接匹配比基类更好,这比基类的基类更好。
#include <algorithm>
#include <iterator>
namespace detail
{
// this gives us infinite types, that inherit from each other
template<std::size_t N>
struct pick : pick<N-1> {};
template<>
struct pick<0> {};
// the overload we want to be preferred have a higher N in pick<N>
// this is the first helper template function
template<typename T>
auto stable_sort(T& t, pick<2>)
-> decltype( t.stable_sort(), void() )
{
// if the container have a member stable_sort, use that
t.stable_sort();
}
// this helper will be second best match
template<typename T>
auto stable_sort(T& t, pick<1>)
-> decltype( t.sort(), void() )
{
// if the container have a member sort, but no member stable_sort
// it's customary that the sort member is stable
t.sort();
}
// this helper will be picked last
template<typename T>
auto stable_sort(T& t, pick<0>)
-> decltype( std::stable_sort(std::begin(t), std::end(t)), void() )
{
// the container have neither a member sort, nor member stable_sort
std::stable_sort(std::begin(t), std::end(t));
}
}
// this is the function the user calls. it will dispatch the call
// to the correct implementation with the help of 'tags'.
template<typename T>
void stable_sort(T& t)
{
// use an N that is higher that any used above.
// this will pick the highest overload that is well formed.
detail::stable_sort(t, detail::pick<10>{});
}
还有其他常用于区分重载的方法,例如精确匹配优于转换,优于省略号。
但是,tag-dispatch 可以扩展到任意数量的选择,并且意图更加清晰。