使用 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
是否是与映射的给定值关联的键。但是,由于无法指定 key
是 constexpr
参数这一事实,我们无法从该参数中提取 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。
我正在努力将用户定义的类型作为 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
是否是与映射的给定值关联的键。但是,由于无法指定 key
是 constexpr
参数这一事实,我们无法从该参数中提取 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。