避免根据模板操作符存在编译某些行

时间:2014-10-16 01:40:56

标签: c++ compiler-errors sfinae

我目前正在创建一个模板容器类,每当模板类具有比较运算符时,我都希望在其中具有排序功能。

使用SFINAE,我可以确定运行时是否存在运算符。但是,当编译下面的代码时,它当然仍然会尝试编译包含sort的行,如果没有为该类指定compare运算符,它将返回编译器错误。

有没有办法避免'如果比较运算符不存在,那么编译该行?不知道这样的程序的命名,像是#ifdef SFINAE'?

template <class UseClass> class Container {
public:
    bool Sort(void) {
        if (CHECK::opCompareExists<UseClass>::value) {
            sort(m_classlist.begin(),m_classlist.end());    //compile error, of course
            return true;
        }
        return false;
    }
private:
    vector<UseClass> m_classlist;
};

也许我根本不应该使用SFINAE ......也许它应该是模板规范?如何工作(基于自动检测操作员不存在)?

1 个答案:

答案 0 :(得分:0)

默认情况下,

std::sort()使用小于运算符(operator<())来比较元素,因此如果类型没有,可以使用表达式SFINAE来排除特定的重载:

template<typename T = UseClass>
auto Sort() -> decltype(std::declval<T>() < std::declval<T>(), bool())
{
    return true;
}

如果替换失败(SomeClass没有operator<()),则编译将失败。

如果这不是你的意图,而是你想要返回true,如果它可以排序,否则就是假,那么你需要一个你可以根据以下重载的特质类:

namespace detail
{
    template<typename T>
    auto has_less_than_impl(int)
        -> decltype(std::declval<T>() < std::declval<T>(), std::true_type());

    template<typename>
    std::false_type has_less_than_impl(...);
}

template<typename T>
struct has_less_than : decltype(detail::has_less_than_impl<T>(0)) { };

template <class UseClass> class Container
{
public:
    bool Sort() { return Sort(has_less_than<UseClass>::value); }
private:
    bool Sort(std::true_type)
    {
        sort(m_classlist.begin(), m_classlist.end());
        return true;
    }

    bool Sort(std::false_type) { return false; }
};

更新:根据您的评论,这里是C ++ 03实现:

template <typename T>
class has_less_than {
    struct Fallback { bool operator<(T const&); };
    struct Derived : T, Fallback {};

    template <typename U, U> struct S;

    template <typename C> static char (&f(S<bool (Fallback::*)(T const&), &C::operator<>*))[1];
    template <typename C> static char (&f(...))[2];

public:
    const static bool value = sizeof(f<Derived>(0)) == 2;
};

namespace detail
{
    template <bool B, typename R = void>
    struct enable_if { typedef R type; };

    template <typename R>
    struct enable_if<false, R> { };
}

template <class UseClass> class Container {
public:
    bool Sort() { return Sort<UseClass>(); }
private:
    template <typename T>
    bool Sort(typename detail::enable_if<has_less_than<T>::value, int>::type = 0) {
        sort(m_classlist.begin(),m_classlist.end());
        return true;
    }

    template <typename T>
    bool Sort(typename detail::enable_if<!has_less_than<T>::value, int>::type = 0) {
        return false;
    }
private:
    vector<UseClass> m_classlist;
};