Определение сопоставимых объектов во время компиляции с Boost.Hana

Я борюсь с наличием пользовательских типов в качестве ключей в hana::map, Я сталкиваюсь с static_assert говоря, что сравнение должно быть возможным во время компиляции. Я реализовал constexpr bool operator== для сочетания (я считаю) всех из них. В чем проблема? Так как мой operator== является constexprмои объекты должны быть сопоставимы во время компиляции, верно?

1 ответ

Решение

Вы должны вернуть 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[]тип возвращаемого значения зависит от ключа. Мы должны как-то извлечь bool представляя, какое значение связано с этим ключом, но это bool должен быть известен во время компиляции (то есть быть константным выражением), чтобы возвращаемый тип зависел от этого. Так внутри 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== возвращает IntegralConstant, Есть больше информации об этом и связанных понятиях здесь и здесь.

Другие вопросы по тегам