C++11静态断言对于可比较类型的相等性?

5
如何在C++11中使用static_assert来确保模板类型符合EqualityComparable概念?

2
请注意,在模板类型参数上使用 static_assert 有时不是最佳选择。通常情况下,您更希望匹配失败,这需要使用 SFINAE,而不是编译失败,static_assert 会导致编译失败。 - Yakk - Adam Nevraumont
1个回答

22
您可以使用以下类型特征:
#include <type_traits>

template<typename T, typename = void>
struct is_equality_comparable : std::false_type
{ };

template<typename T>
struct is_equality_comparable<T,
    typename std::enable_if<
        true, 
        decltype(std::declval<T&>() == std::declval<T&>(), (void)0)
        >::type
    > : std::true_type
{
};

这个句子的英文原文已经非常简洁明了,翻译为:“你可以用这种方式进行测试:”。
struct X { };
struct Y { };

bool operator == (X const&, X const&) { return true; }

int main()
{
    static_assert(is_equality_comparable<int>::value, "!"); // Does not fire
    static_assert(is_equality_comparable<X>::value, "!"); // Does not fire
    static_assert(is_equality_comparable<Y>::value, "!"); // Fires!
}

这是一个实时示例

2
小修正:如果T不是默认可构造的,则无法正常工作 - 将其更改为std :: declval <T>()而不是T() - jrok
1
@jrok:当然。不知道我怎么会忽略那个。谢谢。 - Andy Prowl
严格来说,这并不是100%的EqualityComparable概念检查,因为Commutativity和Transitivity要求没有被检查。但由于它们无法在编译时进行检查,所以我想这并不是什么大问题。 - Rost
1
@ChristopherC:无论您选择declval<T&>还是declval<T>,都将存在一个“非成语化”的签名,该特征不会正确识别。如果我选择了declval<T>,那么具有接受可修改的左值引用的operator ==的类型将被识别为非相等可比较的类型。当然,通过可修改的左值引用进行接受几乎没有意义,但是通过右值引用进行接受甚至更少。 - Andy Prowl
2
std::enable_if 是多余的。 特化可以简化为template<typename T> struct is_equality_comparable< T, decltype(std::declval<T>() == std::declval<T>(), (void)0)> : std::true_type {}; - Matthias
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接