Boost logo

Boost :

Subject: Re: [boost] C++11 Metaprogramming
From: Pyry Jahkola (pyry.jahkola_at_[hidden])
Date: 2012-04-03 16:26:20


On 2012-04-03 15:57:34 +0000, Dave Abrahams said:

>> template <typename Then> struct otherwise {
>> typedef Then type;
>> static constexpr bool value = true;
>> };
>
> Do the uses of constexpr here add anything w.r.t. plain const?

Not to my knowledge (or correct me if it does!). I just acquired this
habit from the way the C++11 standard library defined constants like
the following in the FDIS:

    namespace std {
        template <class T, T v>
        struct integral_constant {
            static constexpr T value = v;
            typedef T value_type;
            typedef integral_constant<T,v> type;
            constexpr operator value_type() { return value; }
        };
    }

>> 5) Using nested variadic templates to get many template parameter
>> packs to play with:
>>
>> (...)
>>
>> template <typename A, typename B>
>> struct concat : detail::con<A>::template cat<B> {};
>
> Interesting formulation. I used:
>
> (...)
>
> template <class ...T1s, class ...T2s>
> struct append_<vector<T1s...>, vector<T2s...> >
> : vector<T1s...,T2s...> {};

Ha! Obviously I had missed the possibility that you can have several
parameter packs in a template specialization as long as the pack
expansions don't appear subsequently in the signature.

> Does the nested class template arrangement have any advantages?

I tried to think of some, but couldn't yet come up with any. I find
your alternative even better.

>> 6) Defining function result and result type at once.
>
> Totally. I have used
>
> // RETURNS() is used to avoid writing boilerplate "->decltype(x) {
> return x; }" phrases.
> //
> // USAGE: auto function(<arguments>) RETURNS(<some-expression>);

I like the trick of requiring a semicolon here.

> Probably it's a good idea to incorporate noexcept: (...)

True. I decided to postpone the use of noexcept until I get other
things to work, so I'm still missing all the little tricks there are
with noexcept. (Keen to hear about them in May!)

>> It can't be used with recursive definitions like here, though:
>>
>> // template <typename A, typename B, typename... C>
>> // auto operator()(A const & a, B const & b, C const &... c) const ->
>> // RETURNS(mul_()(a * b, c...))
>
>> // --> Error: invalid use of incomplete type mul_
>
> Heh, try (*this) instead of mul_(). That works until you try to
> incorporate noexcept as suggested above (at least on GCC 4.7).

Yep, same thing on clang: as soon as I enable noexcept in the
RETURNS(...) macro, it gives "error: invalid use of 'this' outside of a
nonstatic member function".

> // ****** workaround ******
> static mul_ get() noexcept { return mul_(); }

I'm not sure which one is correct here, GCC or Clang, but but this
trick had a similar result: "error: calling 'get' with incomplete
return type 'mul_'".

The only alternative way I could fix it was to define a function
returning a reference, e.g.:

    struct mul_ {
        // ...

        static mul_ const & get() noexcept;
    };

    constexpr mul_ mul = {};

    inline mul_ const & mul_::get() noexcept { return mul; }

> very annoying.

Indeed.

>> 7) Counted template recursion.
>
> Isn't it a bit slicker to do this by creating an argument pack
> of integers and expanding that with get<Is>(t)... ?

Oh, sure! I wonder how I missed that. Yes, converting a template
argument pack into an equal-length index sequence is very useful.

> --8<---------------cut here---------------start------------->8---
> template <class T, T I, class S> struct cons_c;
>
> template <template <class T, T...> class S, class T, T I, T ...Is>
> struct cons_c<T, I, S<T, Is...> >
> : S<T,I,Is...>
> {};
>
> template <class T, T ...Is>
> struct vector_c { typedef vector_c type; };
>
> template <std::size_t N>
> struct count_
> : cons_c<std::size_t, N-1, typename count_<N-1>::type>
> {};
>
> template <>
> struct count_<0>
> : vector_c<std::size_t>
> {};
>
> template <std::size_t N>
> using count = typename count_<N>::type;
>
> #include <tuple>
>
> template <typename F, typename Tuple , std::size_t ...Is>
> auto apply_tuple(F f, Tuple const & t, vector_c<std::size_t, Is...>)
> RETURNS(f(std::get<Is>(t)...));
>
> template <typename F, typename ...T>
> auto apply_tuple(F f, std::tuple<T...> const & t)
> RETURNS(apply_tuple(f, t, count<sizeof...(T)>()));
> --8<---------------cut here---------------end--------------->8---

So thanks, I'm happy to hide this trick into my sleeve! ;)

-- 
Pyry Jahkola · http://pyrtsa.posterous.com
pyry.jahkola_at_[hidden] · http://twitter.com/pyrtsa
Attending C++Now! 2012

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk