Boost logo

Boost :

Subject: Re: [boost] [offtopic] C++11 useful trick
From: Roland Bock (rbock_at_[hidden])
Date: 2012-07-02 04:12:54


On 2012-07-02 01:20, Eric Niebler wrote:
> I recently ran into a limitation in recursive functions that make use of
> decltype in trailing return types. I've come up with a work-around that
> I think is a little non-obvious, so I thought I'd share.
>
> The problem came up while trying to implementing something like a
> variadic back() function. The "obvious" implementation doesn't work:
>
> template<typename T>
> T back(T && t)
> {
> return t;
> }
>
> template<typename T, typename ...U>
> auto back(T && t, U &&... u)
> -> decltype(::back(static_cast<U &&>(u)...)) // ERROR
> {
> return ::back(static_cast<U &&>(u)...);
> }
>
> int main()
> {
> int i = ::back(1,2,3);
> }
>
> The problem occurs on the line marked "HERE". Trouble is, the variadic
> "back" function is not yet in scope until after the return type.
> However, we'd like to use it when specifying the return type.
>
> The solution uses a default function template parameter to make the
> ::back symbol dependent, thereby deferring it's lookup until phase 2,
> when the symbol is visible. Check it:
>
> struct S
> {
> template<typename T>
> static T back(T && t)
> {
> return t;
> }
>
> template<typename T, typename ...U, typename Impl = S>
> static auto back(T && t, U &&... u)
> -> decltype(Impl::back(static_cast<U &&>(u)...))
> {
> return Impl::back(static_cast<U &&>(u)...);
> }
> };
>
> int main()
> {
> int i = S::back(1,2,3);
> }
>
> The trick is the "typename Impl = S" followed by a (now dependent)
> invocation of Impl::back. Voila.
>
> Apologies if this is a known technique, and I'm spamming the list with
> old news. It's news to me.
>

Hmm, I would have done something like this:

// -----------------------------------------------------------------
namespace detail
{
  template<typename T, typename ...U>
  struct back_t
  {
    typedef typename back_t<U...>::type type;
  };

  template<typename T>
  struct back_t<T>
  {
    typedef T type;
  };
}

template<typename T>
T back(T && t)
{
  return t;
}

template<typename T, typename ...U>
typename detail::back_t<U...>::type back(T && t, U &&... u)
{
  return ::back(static_cast<U &&>(u)...);
}

int main()
{
  int i = ::back(1,2,3);
}
// -----------------------------------------------------------------

The advantages I see are that

 * nobody will be confused by the Impl parameter.
 * no need to put back() into a struct

Do you see any drawbacks?

Regards,

Roland


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