Search code examples
c++c++14boost-hana

Create hana tuple with unmovable / noncopyable types


I'm trying to wrap my head around the great boost::hana and try to figure out how to translate some old school tuple code.

Maybe it's a bit special but I have types that are neither copyable nor moveable and want to pack them in a container. Think policy design ...

I guess I'm just not getting how to create a hana tuple in the value world. The way I'm trying doesn't work because make<Tuple>(CompT{}...) needs types that are either copyable or at least moveable.

So most likely this is just not the way to do it. Or is this a limitation of hana?

Thanks!

struct NonMoveable
{
    NonMoveable() = default;
    NonMoveable(const NonMoveable& other) = delete;

    int val;
};

struct Simple { int val; };

template <typename ...CompT>
struct OldSchoolContainer
{
    template <int I>
    auto& getComponent()
    {
        return std::get<I>(components);
    }

    std::tuple<CompT...> components;
};

template <typename ...CompT>
struct HanaContainer
{
    using Args_t = decltype(make<Tuple>(CompT{}...));

    template <int I>
    auto& getComponent()
    {
        return components[int_<I>];
    }

    Args_t components;
};

int main()
{
    OldSchoolContainer<Simple> simpleOsc;
    static_assert(std::is_same<Simple&, decltype(simpleOsc.getComponent<0>())>::value, "");

    HanaContainer<Simple> simpleHanaC;
    static_assert(std::is_same<Simple&, decltype(simpleHanaC.getComponent<0>())>::value, "");


    OldSchoolContainer<NonMoveable> nonmoveableOsc;
    static_assert(std::is_same<NonMoveable&, decltype(nonmoveableOsc.getComponent<0>())>::value, "");

    // !!! this does not compile because hana's tuple closure needs to either move or copy
    HanaContainer<NonMoveable> nonmoveableHanaC;
    static_assert(std::is_same<NonMoveable&, decltype(nonmoveableHanaC.getComponent<0>())>::value, "");

    return 0;
}

Solution

  • You can use the hana::_tuple<...> type almost exactly as std::tuple. Hence, the following works:

    #include <boost/hana/integral_constant.hpp>
    #include <boost/hana/tuple.hpp>
    #include <tuple>
    #include <type_traits>
    namespace hana = boost::hana;
    
    
    struct NonMoveable
    {
        NonMoveable() = default;
        NonMoveable(const NonMoveable& other) = delete;
    
        int val;
    };
    
    struct Simple { int val; };
    
    template <typename ...CompT>
    struct HanaContainer
    {
        template <int I>
        auto& getComponent()
        {
            return components[hana::int_<I>];
        }
    
        hana::_tuple<CompT...> components;
    };
    
    int main()
    {
        HanaContainer<Simple> simpleHanaC;
        static_assert(std::is_same<Simple&, decltype(simpleHanaC.getComponent<0>())>::value, "");
    
        HanaContainer<NonMoveable> nonmoveableHanaC;
        static_assert(std::is_same<NonMoveable&, decltype(nonmoveableHanaC.getComponent<0>())>::value, "");
    
        return 0;
    }