首页 > 解决方案 > Boost Hana 实现自定义序列

问题描述

我面临一种情况,我通常会通过继承来创建自定义类boost::hana::tuple。例如,通过使用以下代码,

template<typename ... args>
struct my_nonworking_custom_tuple_t : public boost::hana::tuple<args ...> //not working!!!
{
    using base = boost::hana::tuple<args ...>;
    //... all other stuff

    auto my_getter() const { return base::operator[](1_c); }
};

然而,这并不像boost::hana::tuple实现为final.

因此,我似乎被迫使用构图,

template<typename ... args>
struct my_custom_tuple_t
{
    //... all other stuff
    boost::hana::tuple<args ...> tup;
    auto my_getter() const { return tup[1_c]; }
};

但是,一旦我这样做,生成的类就不再对 Hana 概念“序列”进行建模,因此我无法应用所有方便的 Hana 方法。

我需要做什么才能变成my_custom_tuple_tHana 序列?

标签: c++boost-hana

解决方案


通常你不需要这样做,但这里有一个指南,用于实现你自己Sequence的以及满足 Boost.Hana 中其他概念的要求。(后者应该对不提供自己的元组实现的最终用户有用。)

从文档中的最小完整定义(MCD)开始hana::Sequence

在那里你会看到,要实现Sequence你的数据类型必须实现make函数以及满足和的Iterable要求Foldable

因此,您必须为其提供实现的 Hana 函数的完整列表如下:

  • at
  • drop_front
  • is_empty
  • make
  • unpack

此外,请注意 Boost.Hana 有两种元组类型tuplebasic_tuple. basic_tuple重量更轻,因此您应该将其用于存储。

要使用 Boost.Hana 的标签调度,您可以实现hana::tag_of或简单地提供hana_tag类型别名作为类的成员。

#include <boost/hana.hpp>
#include <utility>

namespace mine {
    struct my_custom_tuple_tag { };

    template<typename ... args>
    struct my_custom_tuple_t {
        using hana_tag = my_custom_tuple_tag;
        //... all other stuff
        boost::hana::basic_tuple<args ...> tup;

        auto my_getter() const {
            return boost::hana::at_c<1>(tup);
        }
    };
}

namespace boost::hana {
    // Iterable

    template <>
    struct at_impl<mine::my_custom_tuple_tag> {
        template <typename Xs, typename N>
        static constexpr decltype(auto) apply(Xs&& xs, N const&) {
            return at_impl<basic_tuple_tag>(std::forward<Xs>(xs).tup, N{});
        }
    };

    template <>
    struct drop_front_impl<mine::my_custom_tuple_tag> {
        template <typename Xs, typename N>
        static constexpr auto apply(Xs&& xs, N const&) {
            return drop_front_impl<basic_tuple_tag>(std::forward<Xs>(xs).tup);
        }
    };

    template <>
    struct is_empty_impl<mine::my_custom_tuple_tag> {
        template <typename Xs>
        static constexpr auto apply(Xs const& xs) {
            return is_empty_impl<basic_tuple_tag>(xs).tup;
        }
    };

    // Foldable

    template <>
    struct unpack_impl<mine::my_custom_tuple_tag> {
        template <typename Xs, typename F>
        static constexpr auto apply(Xs&& xs, F&& f) {
            return unpack_impl<basic_tuple_tag>(std::forward<Xs>(xs).tup,
                                                std::forward<F>(f));
        }
    };

    // Sequence

    template <>
    struct make_impl<mine::my_custom_tuple_tag> {
        template <typename ...Args>
        static constexpr auto apply(Args&& ...args) {
            return make_impl<basic_tuple_tag>(std::forward<Args>(args)...);
        }
    };

    template <>
    struct Sequence<mine::my_custom_tuple_tag> : std::true_type { };
}

值得注意的是,用于检查的模板Sequence只是一个可选的模板专业化。我确信这只是节省编译时计算的捷径,因为其他概念依赖于检查其所需函数的非默认实现。

https://godbolt.org/z/iaYBFq


推荐阅读