首页 > 解决方案 > SFINAE 没有选择正确的重载解决方案

问题描述

我正在尝试解决一个涉及 SFINAE 的相对简单的旅行。
我的目标是找到对特定类型 T 进行排序的最佳方法。
我有 3 种情况:

  1. type T supports `sort` function
  2. type T supports range i.e. have begin and end functions (lets not include comparability at this point)
  3. type T is not sortable (doesn't support ranges and doesn't have sort function)

所以我写了基本的模板重载并试图从 SFINAE 中受益

#include <iostream>
#include <vector>

struct HaveSort { char c; };
struct HaveRange { char c; HaveSort s; };
struct HaveNone { char c; HaveRange r; };

template<typename T>
HaveSort test_sort(decltype(&T::sort), decltype(&T::sort));

template<typename T>
HaveRange test_sort(decltype(&T::begin), decltype(&T::end));

template<typename T>
HaveNone test_sort(...);

template<typename T, int N>
struct sort_helper;

template<typename T>
struct sort_helper<T, sizeof(HaveSort)>
{
    static void fsort(T& x)
    {
        std::cout << "Type " << typeid(x).name() << " supports sort" << std::endl;
        x.sort();
    }
};

template<typename T>
struct sort_helper<T, sizeof(HaveRange)>
{
    static void fsort(T& x)
    {
        std::cout << "Type " << typeid(x).name() << " supports range" << std::endl;
        std::sort(x.begin(), x.end());
    }
};

template<typename T>
struct sort_helper<T, sizeof(HaveNone)>
{
    static void fsort(T& x)
    {
        std::cout << "Type " << typeid(x).name() << " supports nothing" << std::endl;
    }
};

template<typename T>
void fast_sort(T& x)
{
    sort_helper<T, sizeof(test_sort<T>(NULL, NULL))>::fsort(x);
}


class A {};
class B { void sort() {} };

int main()
{
    static_assert(sizeof(HaveSort) != sizeof(HaveRange), "Find other way to handle HaveSort and HaveRange\n");
    static_assert(sizeof(HaveRange) != sizeof(HaveNone), "Find other way to handle HaveRange and HaveNone\n");

    std::vector<int> V{ 1,9,5,3 };
    A a;
    B b;
    fast_sort(V);
    fast_sort(a);
    fast_sort(b);
}

这输出

Type class std::vector<int,class std::allocator<int> > supports nothing
Type class A supports nothing
Type class B supports nothing

对于所有三个类 - vector<int>, A, B

有谁知道为什么 SFINAE 在这里没有正确过载?
提前致谢。

标签: c++templatesoverloadingsfinae

解决方案


实际上 SFINAE 适用于您的所有类型:

  • A没有sort()// begin()_end()
  • B没有begin()/end()也没有.public sort()
  • std::vector<int>没有sort(),并且&std::vector<int>::begin(类似 for end)是模棱两可的,因为有几个重载(const和非const方法)。

我会做这样的事情:

template <std::size_t N> struct overload_priority : overload_priority<N - 1> {};
template <> struct overload_priority<0> {}; // lowest priority


template<typename T>
auto fsort(T& x, overload_priority<2>) -> decltype(x.sort(), void())
{
    std::cout << "Type " << typeid(x).name() << " supports sort" << std::endl;
    x.sort();
}

template<typename T>
auto fsort(T& x, overload_priority<1>) -> decltype(std::sort(x.begin(), x.end()), void())
{
    std::cout << "Type " << typeid(x).name() << " supports range" << std::endl;
    std::sort(x.begin(), x.end());
}

template<typename T>
void fsort(T& x, overload_priority<0>)
{
    std::cout << "Type " << typeid(x).name() << " supports nothing" << std::endl;
}

template<typename T>
void fast_sort(T& x)
{
    fsort(x, overload_priority<5>{}); // big enough
}

演示


推荐阅读