使用 Boost.Hana 定义编译时 Comparable 对象

Defining compile-time Comparable objects with Boost.Hana

我正在努力将用户定义的类型作为 hana::map 中的键。 我 运行 变成 static_assert 说比较必须是可能的 编译时间。我确实为组合实现了 constexpr bool operator== 的(我相信)所有这些。有什么问题?由于我的 operator==constexpr,我的对象在编译时应该是可比较的,对吧?

您必须 return 来自比较运算符的 integral_constant<bool, ...>,而不是 constexpr bool。以下作品:

#include <boost/hana.hpp>
#include <cassert>
#include <string>
namespace hana = boost::hana;

template <int i>
struct UserDefined { };

template <int a, int b>
constexpr auto operator==(UserDefined<a>, UserDefined<b>) 
{ return hana::bool_c<a == b>; }

template <int a, int b>
constexpr auto operator!=(UserDefined<a>, UserDefined<b>) 
{ return hana::bool_c<a != b>; }

int main() {
    auto m = hana::make_map(
        hana::make_pair(UserDefined<0>{}, std::string{"zero"}),
        hana::make_pair(UserDefined<1>{}, 1)
    );

    assert(m[UserDefined<0>{}] == "zero");
    assert(m[UserDefined<1>{}] == 1);
}

为什么?

要理解为什么 constexpr bool 比较运算符还不够,请考虑 hana::map::operator[]:

的伪实现
template <typename ...implementation-defined>
struct map {
    template <typename Key>
    auto operator[](Key const& key) {
        // what now?
    }
};

operator[] 中,returned 值的 type 取决于键。我们必须以某种方式提取一个 bool 表示哪个值与该键相关联,但是 bool 必须在编译时已知(即是一个常量表达式)才能使 return 类型取决于那个。所以在 operator[] 中,我们需要一个 constexpr bool 来表示 key 是否是与映射的给定值关联的键。但是,由于无法指定 keyconstexpr 参数这一事实,我们无法从该参数中提取 constexpr bool,即使 Key 具有 constexpr bool operator==定义。也就是说,

template <typename Key>
auto operator[](Key const& key) {
    // impossible whatever some_other_key_of_the_map is
    constexpr bool found = (key == some_other_key_of_the_map);

    // return something whose type depends on whether the key was found
}

实现上述目标的唯一方法是做类似

的事情
template <typename Key>
auto operator[](Key const& key) {
    constexpr bool found = decltype(key == some_other_key_of_the_map)::value;

    // return something whose type depends on whether the key was found
}

因此需要 Key::operator== return 一个 IntegralConstant。关于这个和相关概念的更多信息 here and here