具有大量选项的重载分辨率

如果你需要在几个选项之间进行选择,只需通过 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 可以扩展到任意数量的选择,并且意图更加清晰。