|
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