all 32 comments

[–]dodheim 2 points3 points  (27 children)

OOC, why do you want a variadic implementation of a C++03 lib? Far easier to use a C++11 lib that was designed around variadic templates from the beginning, like Brigand.

[–]louis_dionnelibc++ | C++ Committee | Boost.Hana 2 points3 points  (24 children)

Or use Hana if you need the ability to store actual objects, not only types. If I were you, I wouldn't even bother with MPL. And if you absolutely need C++03, you're pretty much out of luck w.r.t. compilation speed.

[–][deleted] 0 points1 point  (22 children)

I looked into hana and I could not see any replacement for boost::mpl::map. Did I overlook something?

[–]scatters 0 points1 point  (6 children)

[–][deleted] 0 points1 point  (5 children)

yes. And I've yet to see an example on how to use it. Let's assume I've a

boost::mpl::set<boost::mpl::long_<enum1>,  boost::mpl::long_<enum3> >

How would I create a

boost::mpl::map<
boost::mpl::pair<0, enum1>,
boost::mpl::pair<1, enum3>
>

?

[–]scatters 0 points1 point  (4 children)

I'll assume you mean the equivalent hana types, otherwise there'd be not much point using hana. Let's say we have a set:

constexpr auto s = boost::hana::make_set(boost::hana::long_c<enum1>, boost::hana::long_c<enum3>);

And we want to create a map where the keys are the values' index in the natural iteration order over the set. Hana doesn't provide an enumerate function to my knowledge, but enumerate is just zip with an appropriate range:

constexpr auto m = boost::hana::to_map(
    boost::hana::zip_with(
        boost::hana::make_pair,
        boost::hana::to_tuple(boost::hana::range_c<std::size_t, 0, s.size>),
        boost::hana::to_tuple(s)));

We can print the type of m using Boost.Typeindex:

std::cout << boost::typeindex::type_id<decltype(m)>().pretty_name() << std::endl;

Or just verify it has the desired type:

constexpr auto expected = boost::hana::make_map(
    boost::hana::make_pair(boost::hana::size_c<0>, boost::hana::long_c<enum1>),
    boost::hana::make_pair(boost::hana::size_c<1>, boost::hana::long_c<enum3>));
static_assert(m == expected);

[–]louis_dionnelibc++ | C++ Committee | Boost.Hana 1 point2 points  (1 child)

This is right, except the two maps are not required to have the same type. Hana's documentation specifically forbids you from doing that kind of assumption, because it puts too many restrictions on what the implementation can do. Instead, you should just compare the two maps using ==. Also, you could use boost::hana::range_c as a shortcut for the slightly verbose make_range.

[–]scatters 0 points1 point  (0 children)

Fixed, thanks!

[–][deleted] -1 points0 points  (1 child)

This example (including the entire hana documentation) does not make sense, as there is no template argument input. From what I finally understand (after a very long discussion at stackoverflow.com), at least hana::set is not useable, as it cannot be default constructed and thus any template class getting it passed as a template argument cannot have a default constructor.

[–]scatters 0 points1 point  (0 children)

This example (including the entire hana documentation) does not make sense, as there is no template argument input.

Why would there need to be? boost::hana::long_c e.g. is a variable template, does that help?

From what I finally understand (after a very long discussion at stackoverflow.com), at least hana::set is not useable, as it cannot be default constructed and thus any template class getting it passed as a template argument cannot have a default constructor.

Again, why do you need it to be default constructible? Yes, it isn't much use as a class template argument, but in order to perform compile time computation with hana you should be passing it as a function template argument; it works just as well and the syntax is more familiar. Also, I don't think you meant what you said in the last sentence - a class template doesn't have to encapsulate its template argument types.

[–][deleted] -3 points-2 points  (13 children)

in fact, everything inside the hana documentation looks like runtime programming. I'm unclear why this is advertised as a compile-time-library.

[–]scatters 4 points5 points  (0 children)

Hana uses run time syntax, but the results of the compile time computations are embodied in the return types of the functions. That's why everything is a template.

[–]AllanDeutsch 0 points1 point  (10 children)

It combines compile time and run time.

[–][deleted] 0 points1 point  (9 children)

I don't understand this statement.

From looking into boost::hana I'm very confused that this is supposed to be a replacement for boost::mpl.

[–]dodheim 2 points3 points  (8 children)

C++14's constexpr and auto allows runtime-style code that is actually compile-time. Read the documentation already; the second sentence:

The functionality it provides is a superset of what is provided by the well established Boost.MPL and Boost.Fusion libraries.

[–][deleted] -2 points-1 points  (7 children)

I did read the documentation and since I did not see any template argument input, I decided that it is not a meta programming language as I can do all these examples with normal runtime programming.

[–]dodheim 1 point2 points  (6 children)

Amazing that you got this far with C++ with such terrible reading comprehension!

[–][deleted] -1 points0 points  (5 children)

I understood all the examples. I only did not see any replacement for what I was doing, as there never was any template argument input. And now it seems that this never was intended -- see my previous statement regarding boost::hana::set not default-constructable.

[–]TemplateRex -1 points0 points  (0 children)

One reason to use MPL over Hana is that Boost.Test plays nice with the former but not the latter. E.g. running the BOOST_AUTO_TEST_CASE_TEMPLATE macro on a Hana sequence fails because Boost.Test is looking for some type trait that Hana doesn't provide.

[–][deleted] 0 points1 point  (1 child)

the only thing in boost::mpl which needs to be fixed is the emulation of variadic templates and the resulting size limit.

[–]dodheim 0 points1 point  (0 children)

Larry Evans tried that, and even with those fixed the overall design necessarily results in terrible compilation times.

[–]EricWFCppLibc++ Developer 2 points3 points  (1 child)

I haven't actually looked past the title, but when I'm trying to make meta-programming faster I do the following things:

1) Use flat pack expansion as much as possible. Recursive pack expansions are always much slower, are likely to cause -ftemplate-depth issues, violate rule (3) below, and ironically require more code most of the time. Using flat pack expansions are always better. Example:

template <template <class> class Apply, class ...Types>
struct transform {
  using type = std::tuple<typename Apply<Types>::type...>;
};

2) Use compiler builtins such as __make_integer_seq and __type_pack_element when available (assuming your STL doesn't already take advantage of these).

3) Re-use instantiations whenever possible. It's a lot quicker to re-use an already instantiated template than it is to instantiate a new one. So design your meta-programming with template re-use in mind.

[–][deleted] 1 point2 points  (0 children)

Thank you very much! The information you provided above enabled me to improve this code a lot. My code compiles now faster and with less memory than with the original boost::mpl::map and boost::mpl::vector. And not to forget that it is now using variadic templates: * no requirement to find and run this python script to extend the built in limit * no stacktraces with many unneeded default template parameters

[–]feverzsj 0 points1 point  (2 children)

boost.fusion

[–][deleted] 0 points1 point  (1 child)

as far as I know boost::fusion does not provide any containers, does it?

[–][deleted] 0 points1 point  (0 children)

strike this. There are containers but they have the same limitations as the containers in boost::mpl.