首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使std::可选的运行时单与Hana?

如何使std::可选的运行时单与Hana?
EN

Stack Overflow用户
提问于 2021-02-14 16:26:41
回答 1查看 177关注 0票数 2

类型hana::optional表示

可选值,其可选性在编译时已知。

除其他外,它还模拟了Monad的概念。因为它是编译时可选的,所以如果我尝试在运行时中选择一个非空的hana::optional (没有包装另一个hana::optional ),那么在运行时会发生什么问题是没有意义的,因为这个错误会在编译时被捕获。

但是运行时间的可选性呢?

下面是我试图使std::optional (而且只有它,我没有提出一个可能的一般概念,这也是boost::optional可以满足的) hana::Monad,我想知道这是否是正确的方法:

代码语言:javascript
复制
#include <assert.h>
#include <boost/hana/chain.hpp>
#include <optional>
#include <stdexcept>
#include <type_traits>
namespace hana = boost::hana;

template<typename T, typename = void>
struct has_value_type : std::false_type {};
template<typename T>
struct has_value_type<T, std::void_t<typename T::value_type>> : std::true_type {};
template<typename T>
bool constexpr has_value_type_t = has_value_type<T>::value;

namespace boost::hana {

    template<typename T>
    struct transform_impl<std::optional<T>> {
        template <typename Opt, typename F>
        static constexpr auto apply(Opt&& o, F&& f) {
            return o.has_value() ? std::make_optional(f(o.value())) : std::nullopt;
        }
    };

    template<typename T>
    struct flatten_impl<std::optional<T>> {
        template <typename X>
        static constexpr auto apply(X&& x) {
            if constexpr (has_value_type_t<typename X::value_type>)
                return (x.has_value() && x.value().has_value()) ? x.value() : std::nullopt;
            else {
                if (!x.has_value())
                    return std::nullopt;
                else
                    throw std::runtime_error("std::optional<non_stdoptional_type> can't be flattened!");
            }
        }
    };

    template<>
    struct flatten_impl<std::nullopt_t> {
        template <typename X>
        static constexpr auto apply(X&&) {
            return std::nullopt;
        }
    };
}


int main() {
    assert(hana::flatten(std::optional<std::optional<int>>{3}) == std::optional<int>{3});
    assert(hana::flatten(std::optional<int>{}) == std::optional<int>{});
    assert(hana::flatten(std::nullopt) == std::optional<int>{});
    //assert(hana::flatten(std::optional<int>{2}) == std::optional<int>{}); // throws
}
EN

回答 1

Stack Overflow用户

发布于 2021-02-15 20:36:21

有一些改进是可以做的。

Boost.Hana使用标记分派系统来专门化impl结构。这简化了专门化,但也防止了外部impl结构与内部函数模板实例化的笛卡儿积。

而且,如果您使用value_type来检测嵌套的可选选项,考虑到满足此约束的类型范围很广,则会出现错误。如果您使用hana::is_a<optional_tag, X>,标记系统也会在这方面有所帮助。

这个更具体的约束也消除了对嵌套可选项执行运行时检查的需要,因为信息本身就在类型中。optional<optional<...>>

专门用于flatten_impl<nullopt_t>是不正确的,因为您不能通过transform运行它。我不认为这是必要的。

下面是一个简化的版本,它还演示了您可以转换类型。也是警员!

代码语言:javascript
复制
#include <assert.h>
#include <boost/hana/core/is_a.hpp>
#include <boost/hana/core/tag_of.hpp>
#include <boost/hana/flatten.hpp>
#include <optional>
#include <string>
namespace hana = boost::hana;

struct my_optional_tag { };

namespace boost::hana {

    template <typename T>
    struct tag_of<std::optional<T>> {
        using type = my_optional_tag;
    };

    template <>
    struct transform_impl<my_optional_tag> {
        template <typename Opt, typename F>
        static constexpr auto apply(Opt&& o, F&& f) {
            using ResultValue = decltype(std::forward<F>(f)(std::forward<Opt>(o).value()));
            using Result = std::optional<std::decay_t<ResultValue>>;
            return o.has_value() ? Result(std::forward<F>(f)(std::forward<Opt>(o).value())) :
                                   Result(std::nullopt);
        }
    };

    template <>
    struct flatten_impl<my_optional_tag> {
        template <typename X>
        static constexpr auto apply(X&& x) {
            using Nested = decltype(std::forward<X>(x).value());
            static_assert(is_a<my_optional_tag, Nested>, "must have nested optional");
            return std::forward<X>(x).value_or(Nested(std::nullopt));
        }
    };
}


int main() {
    // Functor
    static_assert(hana::transform(std::optional<int>{41}, [](int x) { return x + 1.0f; }) ==
            std::optional<float>{42});

    // Monad
    static_assert(hana::flatten(std::optional<std::optional<int>>{3}) == std::optional<int>{3});

    constexpr auto inc = [](int x) { return std::optional{x + 1.0f}; };
    static_assert(hana::chain(std::optional<int>{5}, inc) == std::optional{6.0f});

    static_assert(hana::flatten(std::optional<std::optional<int>>{std::nullopt}) == std::nullopt);

    // hana::flatten(std::optional<int>{3}); // compile-time error
}

https://godbolt.org/z/7KWGn6

请注意,我忽略了hana::lifthana::ap的实现,这两个实现是hana::Applicative所必需的,后者是hana::Monad所必需的(在文档化的最小完全定义中)。我会把这个留给读者。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66197453

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档