Search code examples
c++functional-programmingc++14template-meta-programmingboost-hana

How can I make the std::vector class a Sequence so that it can be passed to boost::hana::group?


I want the following code to compile and work:

#include <boost/hana/group.hpp>
#include <functional>
#include <vector>
int main() {
    std::vector<int> x = {1,1,3,4};
    auto groups = boost::hana::group(x, std::equal_to<>{});
}

An attempt to compile errors like this:

$ g++ -std=c++2a deleteme.cpp && ./a.out
In file included from deleteme.cpp:1:
/usr/include/boost/hana/group.hpp: In instantiation of ‘constexpr auto boost::hana::group_t::operator()(Xs&&, Predicate&&) const [with Xs = std::vector<int>&; Predicate = std::equal_to<void>]’:
deleteme.cpp:6:44:   required from here
/usr/include/boost/hana/group.hpp:55:42: error: static assertion failed: hana::group(xs, predicate) requires 'xs' to be a Sequence
   55 |         static_assert(hana::Sequence<S>::value,
      |                                          ^~~~~
/usr/include/boost/hana/group.hpp:59:28: error: use of deleted function ‘static constexpr auto boost::hana::deleted_implementation::apply(T&& ...) [with T = {std::vector<int, std::allocator<int> >&, std::equal_to<void>}]’
   59 |         return Group::apply(static_cast<Xs&&>(xs),
      |                ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
   60 |                             static_cast<Predicate&&>(pred));
      |                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/boost/hana/core/dispatch.hpp:14,
                 from /usr/include/boost/hana/drop_front.hpp:18,
                 from /usr/include/boost/hana/concept/iterable.hpp:20,
                 from /usr/include/boost/hana/at.hpp:16,
                 from /usr/include/boost/hana/group.hpp:15,
                 from deleteme.cpp:1:
/usr/include/boost/hana/detail/dispatch_if.hpp:21:31: note: declared here
   21 |         static constexpr auto apply(T&& ...) = delete;
      |                               ^~~~~

Therefore I understand that the reason is that std::vector does not satisfy the concept of Sequence, but how do I enforce that it does?

I've been giving a look at /usr/include/boost/hana/fwd/concept/sequence.hpp and /usr/include/boost/hana/concept/sequence.hpp, but for now the template meta-metaprogramming in those files is still a bit to heavy for me to understand it without any help.

This is an excerpt from Hana's documentation, which I think addresses the question. The point is that I don't how I can translate that prescriptions to code:

For this reason, it is necessary to specialize the Sequence metafunction in Hana's namespace to tell Hana that a type is indeed a Sequence. Explicitly specializing the Sequence metafunction can be seen like a seal saying "this data type satisfies the additional laws of a Sequence", since those can't be checked by Hana automatically.


Solution

  • While it is possible to implement some of the concepts in Boost.Hana with types that involve different dimensions known only at run-time, Boost.Hana.Sequence and some of the concepts that are a part of its "Minimal Complete Definition" require length and elements to be known at compile-time.

    • Foldable requires that the length be known at compile-time.
    • Iterable requires that each element be accessible at compile-time.
    • Sequence requires Foldable and Iterable.

    The group function requiring a Sequence and the run-time length of std::vector make this impossible.

    The section Computational Quadrants in the Boost.Hana manual elaborates on algorithms requiring compile-time vs run-time information.

    (The Group concept is likely doable, but I don't think that is part of the question.)

    Regarding the comments about specializing third party templates for standard types, it is possible but considered bad form. The solution is to make a wrapper type of some kind or provide your own concepts.

    Edit:

    A comment suggested an example of implementing std::array as a Sequence since its length is known at compile-time. While I can't find a silver bullet in the "Laws" of Sequence that forbid homogeneously typed lists, I can say that the premise of Sequence is working with heterogeneously typed data structures. Elements may contain run-time data, but all of the predicates in the algorithms rely exclusively on "compile-time" information so functions like group would be completely useless for std::array. (This is explained in the aforementioned link)