我一直在通过SFINAE和Curiously Recurring模板模式成语实现总排序,现在已经有一段时间了。总的想法如下:奇怪的循环模式和Sfinae
- 定义用于检查关系运算符模板(
<
,>
等) - 定义限定总体排序操作符基类。
- 定义运算符检测的基类。
- 从基类继承。
为简单起见,本例中我忽略了==
和!=
运算符。
关系运算符检测
我第一次定义类静态检查类是否定义了特定的功能。例如,在此我检测到存在小于运算符或operator<
。
template <typename T>
class has_less
{
protected:
template <typename C> static char &test(decltype(std::declval<C>() < std::declval<C>()));
template <typename C> static long &test(...);
public:
enum {
value = sizeof(test<T>(0)) == sizeof(char)
};
};
template <typename T>
constexpr bool has_less_v = has_less<T>::value;
总订货
然后我定义了实现从给定的运营商总排序,例如,从小于运算符,我会用定义总排序如下类别:
template <typename T>
struct less_than_total
{
bool operator>(const T &t) { return t < static_cast<T&>(*this); }
bool operator>=(const T &t) { return !(static_cast<T&>(*this) < t); }
bool operator<=(const T &t) { return !(t < static_cast<T&>(*this)); }
};
基类
我然后定义一个通过检测实现的操作符来创建typedef来实现其余操作符的单个基类。
template <bool B, typename T, typename F>
using conditional_t = typename std::conditional<B, T, F>::type;
template <typename T>
using total_ordering = conditional_t< // has_less
has_less_v<T>,
less_than_total<T>,
conditional_t< // has_less_equal
has_less_equal_v<T>,
less_equal_total<T>,
conditional_t< // has_greater
has_greater_v<T>,
greater_total<T>,
conditional_t< // has_greater_equal
has_greater_equal_v<T>,
greater_equal_total<T>,
symmetric<T> // symmetry
> // has_greater_equal
> // has_greater
> // has_less_equal
>; // has_less
继承
所有这些措施,单独工作。但是,当我使用奇怪的循环模式实际继承基类时,所得到的类仅实现这些运算符中的一个,并且检测算法失败。
例
我的问题归结为一个最小的例子包括核心部分组成:操作者检测(has_less
,has_greater
),总排序实现(total
),一个简化的基类(total
) ,以及使用这些关系运算符的简单结构(A
)。
#include <type_traits>
// DETECTION
template <typename T>
class has_less
{
protected:
template <typename C> static char &test(decltype(std::declval<C>() < std::declval<C>()));
template <typename C> static long &test(...);
public:
enum {
value = sizeof(test<T>(0)) == sizeof(char)
};
};
template <typename T>
class has_greater
{
protected:
template <typename C> static char &test(decltype(std::declval<C>() > std::declval<C>()));
template <typename C> static long &test(...);
public:
enum {
value = sizeof(test<T>(0)) == sizeof(char)
};
};
// TOTAL ORDERING
template <typename T>
struct less_than_total
{
bool operator>(const T &t) { return t < static_cast<T&>(*this); }
bool operator>=(const T &t) { return !(static_cast<T&>(*this) < t); }
bool operator<=(const T &t) { return !(t < static_cast<T&>(*this)); }
};
template <typename T>
struct symmetry
{};
template <bool B, typename T, typename F>
using conditional_t = typename std::conditional<B, T, F>::type;
template <typename T>
struct total: conditional_t<
has_less<T>::value,
less_than_total<T>,
symmetry<T>
>
{};
// TEST
struct A: total<A>
{
bool operator<(const A &r)
{
return true;
}
};
int main(void)
{
static_assert(has_less<A>::value, "");
static_assert(has_greater<A>::value, "");
return 0;
}
理想情况下,这个例子将编译,但是,我得到:
$ clang++ a.cpp -o a -std=c++14
a.cpp:79:5: error: static_assert failed ""
static_assert(has_less<A>::value, "");
^ ~~~~~~~~~~~~~~~~~~
a.cpp:80:5: error: static_assert failed ""
static_assert(has_greater<A>::value, "");
不幸的是,基类不是继承期间检测操作员和SFINAE不检测比该小还是大在最终的类中的运算符。
问题和后续
我想知道为什么会失败,因为我一直在做成员函数检测成员类型检测很长一段时间没有问题的好奇循环模式。假设我的代码没有直接的问题,是否有任何解决方法来实现这种方式的总排序?
编辑
我能达到什么样我想用std::enable_if
的一个子集。在这种情况下,唯一简单的答案是按照operator<
的规定实施所有操作,然后执行该操作员的总排序。
template <typename T>
struct total
{
template <typename U = T>
typename std::enable_if<has_less<U>::value, bool>::type
bool operator>(const T &l, const T &r) { return r < t; }
};
如果仍希望为什么通过SFINAE我的操作者检测传承过程中出现故障,但成功的继承方法的答案。
你在那个例子中期望发生什么? – mascoj
@mascoj,理想情况下,它会编译。我会编辑我的问题。 –