3

I am trying to generate a type that is using template-of-templates using boost::hana but ran into trouble.

I have the following classes

template<template<typename> typename BarModel>
struct Foo {
    BarModel<double> bar;
}

template<typename T>
struct BarOne {
    T x;
}

template<typename T>
struct BarTwo {
    T y;
}

I now want to create a Foo<BarImpl> for each of the BarX<T> classes:

auto bar_types = hana::tuple_t<hana::template_t<BarOne>, hana::template_t<BarTwo>>;

hana::for_each(bar_types, [](auto t) {
    auto footype = SOMETHING(t);
});

Problem, is I am not sure how this is supposed to be done. My first attempt was to do

using BarT = typename decltype(t)::type;
auto bar_t = BarT(); // template_t, can create BarX<T> classes

auto foo_t = hana::template_<Foo>; // <-- FAIL
auto foo_bar_t = foo_t(bar_t);

but this fails with a

error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class ...> class F> constexpr const boost::hana::template_t<F> boost::hana::template_<F>’

note:   expected a template of type ‘template<class ...> class F’, got ‘template<template<class> class BarModel> class Foo’

The note suggests that hana::template_ does not work with template-of-templates. Is this the case? If so, is there an alternative solution?

Hannes Ovrén
  • 21,229
  • 9
  • 65
  • 75

1 Answers1

1

Boost.Hana does not support this directly, but implementing it for this case is just a few lines of code.

Check it out:

#include <boost/hana.hpp>

namespace hana = boost::hana;

template <template <template <typename...> class> class F>
struct template_template_t
{
  template <template <typename...> class G>
  constexpr auto operator()(hana::basic_type<hana::template_t<G>>) const
    -> hana::type<F<G>>
  { return {}; }
};

template <template <template <typename...> class> class F>
constexpr auto template_template = template_template_t<F>{};

/*****/

template <template <typename...> class BarModel>
struct Foo {
  BarModel<double> bar;
};

template <typename T>
struct BarOne {
  T x;
};

template <typename T>
struct BarTwo {
  T y;
};

int main() {
  constexpr auto bar_types = hana::tuple_t<hana::template_t<BarOne>, hana::template_t<BarTwo>>;

  BOOST_HANA_CONSTANT_ASSERT(hana::equal(
    hana::transform(bar_types, template_template<Foo>)
  , hana::tuple_t<Foo<BarOne>, Foo<BarTwo>>
  ));
}
Jason Rice
  • 1,686
  • 1
  • 12
  • 17
  • This seems to work, thanks! Since my template class was declared as `template – Hannes Ovrén Dec 08 '17 at 11:04
  • It should mean that it matches zero or more typename template parameters. I guess it has to match the signature exactly which is probably why it is not in the library. http://en.cppreference.com/w/cpp/language/parameter_pack – Jason Rice Dec 08 '17 at 17:06
  • 1
    To be honest, I had never thought of this use case; that's why it's not in the library. But your observation is a good reason to keep them out of the library (or to fix the language, because that seems weird). – Louis Dionne Dec 13 '17 at 05:04
  • @LouisDionne Perhaps it has already been addressed. This is currently only partially implemented in Clang: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0522r0.html – Jason Rice Dec 19 '17 at 17:48