ericniebler / meta

A tiny metaprogramming library
Boost Software License 1.0
302 stars 46 forks source link

Add count, count_if, and let #13

Closed ericniebler closed 9 years ago

ericniebler commented 9 years ago

In ericniebler/range-v3@970ce2e, I added meta::count, meta::count_if, and meta::let. These need to be merged.

ericniebler commented 9 years ago

Just for fun, find_index with let:

template<typename T, typename List>
using find_index = let<
    var<_a, find<List, T>>,
    lazy::if_<
        std::is_same<_a, list<>>,
        meta::npos,
        lazy::minus<size<List>, lazy::size<_a>>>>;
gnzlbg commented 9 years ago

You are just showing off, come on, admit it.

On Thu, Feb 26, 2015 at 10:30 PM, Eric Niebler notifications@github.com wrote:

Just for fun, find_index with let:

template<typename T, typename List>using find_index = let< var<a, find<List, T>>, lazy::if< std::is_same<_a, list<>>, meta::npos, lazy::minus<size, lazy::size<_a>>>>;

— Reply to this email directly or view it on GitHub https://github.com/ericniebler/meta/issues/13#issuecomment-76277714.

ericniebler commented 9 years ago

You know you want it.

gabyx commented 9 years ago

This meta library is cool, and newbies like me can learn alot from the implementations: 2 questions: what is the

void_<C<eval<impl<Ts, Args>>...>>

in the lambda implementation, this evaluates always to void right? is that somehow to enforce pattern matching =) or to trick the compiler to know something beforhand or is it SFINAE?

thanks :-)

ericniebler commented 9 years ago

It's SFINAE. That specialization will only be selected if C<eval<impl<Ts, Args>>...> is well-formed.

ericniebler commented 9 years ago

There's a lot about Meta's implementation that is not obvious. I could write an entire blog post about the implementation of meta::quote, for instance:

template<template<typename...> class C>
struct quote
{
private:
    template<typename, typename = quote, typename = void>
    struct impl
    {};
    template<typename...Ts, template<typename...> class D>
    struct impl<list<Ts...>, quote<D>, void_<D<Ts...>>>
    {
        using type = D<Ts...>;
    };
public:
    // Indirection here needed to avoid Core issue 1430
    // http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1430
    template<typename...Ts>
    using apply = eval<impl<list<Ts...>>>;
};

Currently, clang is the only compiler that gets it 100% correct. (I have reason to think gcc-5 will get it right, too.) This part of the C++ standard is very underspecified, so I can't be completely sure this is "right", or even that the committee knows what "right" should be here.

What I'm saying is, there's a lot you won't get just by studying Meta's implementation. I would need to document it.

ericniebler commented 9 years ago

Fixed in 4822936

gabyx commented 9 years ago

once you have little time, it would be a lot usefull to read a post about these subtle things, like meta::quote or so :-)

under the hood there is some much involved. when I see the intricacies and all the workarounds in c++ especially with templates I am always asking my self is this language not gone over board a long time ago :) but I like it, its fast and cool :-) and it makes you think a little bit (as a beginner im templates) about what the compiler can do and what it can simply not guess =)

thanks for the good work =)

Am 28.02.2015 um 03:22 schrieb Eric Niebler notifications@github.com:

Closed #13.

— Reply to this email directly or view it on GitHub.

ericniebler commented 9 years ago

For the record, I've discovered something very interesting about let and defer. Since they (and lambda) do SFINAE consistently and turn into a no-op when any substitution failure occurs, they can be used to do compile-time computations that can fail. Consider:

// This might or might not have a nested ::type typedef
template<typename T>
struct difference_type
  : detail::difference_type<uncvref_t<T>>
{};

template<typename T>
struct size_type
  : std::make_unsigned<meta::eval<difference_type<T>>>
{};

difference_type may or may not have a nested ::type, but size_type acts like the nested ::type is always there and issues a hard error when it's not. size_type could instead be written like this:

template<typename T>
struct size_type
  : meta::lazy::let<std::make_unsigned<meta::lazy::eval<difference_type<T>>>>
{};

Now size_type only has a nested ::type if difference_type does, too.

[*] This only works on clang at the moment. Gcc has a bug that will supposedly be fixed for 5.0.

gnzlbg commented 9 years ago

[...] let and defer. Since they (and lambda) do SFINAE consistently and turn into a no-op when any substitution failure occurs

What is the best way to detect if an error occurred?

ericniebler commented 9 years ago

Not sure I understand the question. If an error occurred where?

pfultz2 commented 9 years ago

Not sure I understand the question. If an error occurred where?

I think what Gonzalo is referring to is how can we tell why the metafunction can't be called, since this produces a similiar problem to using a trailing decltype as well.

ericniebler commented 9 years ago

If you're getting a substitution failure trying to apply a metafunction, you have to move the logic of your metafunction to a non-immediate context, where it will cause a hard error with a backtrace.