On Tue, Feb 21, 2017 at 4:32 PM, Peter Dimov via Boost < boost@lists.boost.org> wrote:
Klemens Morgenstern wrote:
Am 21.02.2017 um 14:11 schrieb Bruno Dutra via Boost:
This is by the way another advantage of Metal, since all of its types > are precisely defined and friendly to pattern matching.
I think that's your main selling point. Afaik Hana also relys on concepts more than on actual types; i.e. the result types are not completely specified.
This is a false dilemma; it's possible to take 'concepts' and return completely specified types.
There are other legitimate reasons to prefer strictness in the arguments though - SFINAE friendliness is one. And there are reasons to prefer concept-ness. Such as for instance
mp_transform<std::add_const_t, std::shared_ptr<X>> // std::shared_ptr<X const>
I'm glad you mentioned it, indeed there is no need for compromises there, we can have both, but I forgot to discuss how Metal addresses this. As a tool that makes it possible to drive overload resolution through SFINAE, it was a very important design goal for Metal from the very beginning that _everything_ it provides must be SFINAE friendly no matter what. In the beginning the concepts Metal was based on were more flexible and made it possible for example that any template specialization be used as a List. That alone however opens a whole trunk of worms, because one has to deal with stuff like this: join<std::tuple<>, std::map<X, Y>, std::unique_ptr<Z>> Should this be valid and if so what should be the result? One might think that std::tuple<X, Y, Z> would be the obvious answer, but how about default template parameters that both std::metal and std::unique_ptr have for their trailing parameters? Should it then be std::tuple<X, Y, std::less<X>, std::allocator<std::pair<X const, Y>>, Z, std::default_delete<Z>>? But why should the result List "type" be std::tuple? Shouldn't it instead by disallowed since the List "types" are not all the same? Conundrums like these made it very tricky to implement even the simplest of the algorithms and had a inevitable impact on performance. So I decided to simplify the concepts to the minimum necessary to express their underlying semantics, while providing helpers like metal::as_list and metal::as_number that translate from List-like and Number-like things into strict Metal Lists and Numbers. This proved to be the best design, because the implementation simplified dramatically, performance improved and metal::as_* helpers could be given maximum flexibility to convert the widest variety of *-like things into their equivalents. Your example is implemented in Metal like this using _ = metal::transform<metal::lambda<std::add_const_t>, metal::as_list<std::shared_ptr<X>>>; // metal::list<X const> metal::apply<metal::lambda<std::shared_ptr>, _> // std::shared_ptr<X const> Admittedly a bit verbosier, but not too bad. .