我目前正在创建一个模板容器类,每当模板类具有比较运算符时,我都希望在其中具有排序功能。
使用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 ......也许它应该是模板规范?如何工作(基于自动检测操作员不存在)?
答案 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;
};