# Overview

If you've been following this article series, this is the article you've been waiting to read! It is the one where I show the final versions of `apply()`

and `apply_tuple()`

. These versions have the following features:

- perfect forwarding of all tuple elements to the corresponding arguments of a function (as with all previous versions), and,
- rvalue template argument deduction is used to reduce the previous solution's
`apply_tuple()`

and`apply_tuple_impl::apply_tuple()`

total of eight (8) functions to four (4),

This article will present the full solution while briefly discussing the elements that make it work.

Update (Feb. 15, 2012):After posting this article, I realized I missed a few (obvious!) simplifications to the code which make it substantially easier to read and understand. The main change was to make`apply_tuple()`

use an easy-to-use template alias as a compile-time type function guard for`std::enable_if`

. A non-cosmetic change was also made as well: the`apply_tuple_return_type_impl()`

prototype was modified to use`std::get`

to remove any possibility of any type mismatches (e.g., differences with const/volatile qualifiers) within the code. I have replaced the previous code and updated the text only in places that make specific code references that would otherwise no longer match the code.

# Supporting Code

## Required `#include`

Files

The following are the required `#include`

files:

#include <tuple>

#include <functional>

#include <type_traits>

## Computing The Indices

In order to extract the elements of a `std::tuple`

, the tuple index is needed as a template parameter, and, to extract all elements of a tuple in a single parameter expansion, a complete set of tuple parameter indices is needed to index the provided tuple. This solution stored the indices using the following type:

struct indices;

which has no definition since there will no (run-time) instance of `indices`

created.

## Generating The Indices

Previously, the indices were generated in a slightly different way. In order to make it easier to reduce the number of `apply_tuple()`

-related functions from eight (8) to four (4), the method of generating `indices`

was changed. Now, to generate the indices, one uses `make_seq_indices<BEGIN,END>`

where `BEGIN`

is the starting index (i.e., `0`

) and `END`

is one past the last index. Thus the definition of `make_seq_indices`

and its supporting code is:

struct make_seq_indices_impl;

template <std::size_t Begin, std::size_t End, std::size_t... Indices>

struct make_seq_indices_impl<Begin, End, indices<Indices...>>

{

using type =

typename

make_seq_indices_impl<Begin+1, End,indices<Indices..., Begin>

>::type

;

};

template <std::size_t End, std::size_t... Indices>

struct make_seq_indices_impl<End, End, indices<Indices...>>

{

using type = indices<Indices...>;

};

template <std::size_t Begin, std::size_t End>

using make_seq_indices =

typename make_seq_indices_impl<Begin, End, indices<>>::type;

## Indirectly Determining the Return Type

The first argument to `apply()`

and `apply_tuple()`

is a function or a functor. For the code to work, one needs to be able to easily determine the return type without *directly* using template template parameters within `apply_tuple()`

. I came up with a clever way to do this *only* using function prototypes:

using return_type = typename std::result_of<F>::type;

template <typename Tuple>

constexpr std::size_t tuple_size()

{

return std::tuple_size<typename std::decay<Tuple>::type>::value;

}

template <

typename Op,

typename T,

template <std::size_t...> class I,

std::size_t... Indices

>

constexpr auto apply_tuple_return_type_impl(

Op&& op, T&& t, I<Indices...>

)

-> return_type<

Op(decltype(std::get<Indices>(std::forward<T>(t)))...)

>;

template <typename Op, typename T>

constexpr auto apply_tuple_return_type(Op&& op, T&& t)

-> decltype(

apply_tuple_return_type_impl(

op, t, make_seq_indices<0,tuple_size<T>()>{}

)

);

where:

`return_type`

and`tuple_size`

are convenience compile-time type functions, and,`apply_tuple_return_type`

accepts forwarded types and passes them to`apply_tuple_return_type_impl`

for template argument deduction so that function's/functor's return type can be determined.

The trick here is to:

- use function prototypes to help ensure run-time code for these functions is never generated,
- use function prototypes to trigger template argument deduction,
- use the
`auto`

return type to permit the use of`std::result_of`

to find the return type of`Op(OpArgs...)`

, and, - the
`auto`

return type to allow`decltype`

to be used with the function's arguments applied to`apply_tuple_return_type_impl`

to enable computing the return type.

A consequence of the above is that it allows any client code to determine the return type of a function/functor *without* directly using template template parameters. For example, later in this article `apply_tuple_return_type_impl`

is used like this:

std::forward<Op>(op),

std::forward<Tuple>(t)

))

Since template template parameters are not (directly) used used to determine the types that will be passed to the function/functor, there is no need to write both lvalue and rvalue overloaded functions to handle the tuple parameter. Since the above definition also uses the same function, `std::get`

, to determine tuple element type as `apply_tuple()`

no type mismatches will occur as a result of using this prototype and the `apply_tuple()`

functions.

Aside:Ensuring that template template parameters need not be directly used along with another item mentioned later was key to reducing the number of functions required from eight (8) to four (4) with`apply_tuple`

and`apply_tuple_impl::apply_tuple()`

.

## Helper Functions For Readability

Without the following definitions, the presented code is harder to read and understand:

constexpr bool is_void()

{

return std::is_void<T>::value;

}

template <typename F>

constexpr bool returns_void()

{

return std::is_void<return_type<F>>::value;

}

template <bool Cond, typename T>

using enable_if = typename std::enable_if<Cond,T>::type;

template <typename Ret>

using if_returns_void_case = enable_if<is_void<Ret>(),Ret>;

template <typename Ret>

using if_returns_nonvoid_case = enable_if<!is_void<Ret>(),Ret>;

where:

`is_void`

,`returns_void`

, and`enable_if`

were defined to avoid having to write`typename`

and`::type`

in numerous places,`if_returns_nonvoid_case`

invokes`std::enable_if`

producing a valid type when`op`

does not return`void`

, and,`if_returns_void_case`

invokes`std::enable_if`

producing a valid type when`op`

returns`void`

.

These definitions will beautify the code below.

# Defining `apply()`

and `apply_tuple()`

## Definition of `apply()`

Recall that the definition of `apply()`

does not use tuples: it simply forwards all arguments after the first argument to `Op`

. So its definition remains unchanged:

inline auto apply(Op&& op, Args&&... args)

-> if_returns_nonvoid_case<return_type<Op(Args...)>>

{

return op( std::forward<Args>(args)... );

}

template <typename Op, typename... Args>

inline auto apply(Op&& op, Args&&... args)

-> if_returns_void_case<return_type<Op(Args...)>>

{

op( std::forward<Args>(args)... );

}

Certainly, this was the easy case! ðŸ™‚

## Definition of `apply_tuple()`

The definitions below forwards all tuple elements to a functor or a function:

template <typename Indices, typename Ret, typename Enable = Ret>

struct apply_tuple_impl;

// void return case...

template <

template <std::size_t...> class I, std::size_t... Indices,

typename Ret

>

struct apply_tuple_impl<I<Indices...>, Ret, void>

{

template <typename Op, typename T>

inline static Ret apply_tuple(Op&& op, T&& t)

{

op(

std::forward<

decltype(std::get<Indices>(std::forward<T>(t)))

>(std::get<Indices>(std::forward<T>(t)))...

);

}

};

// non-void return case...

template <

template <std::size_t...> class I, std::size_t... Indices,

typename Ret

>

struct apply_tuple_impl<

I<Indices...>,

Ret,

if_returns_nonvoid_case<Ret>

>

{

template <typename Op, typename T>

inline static Ret apply_tuple(Op&& op, T&& t)

{

return op(

std::forward<

decltype(std::get<Indices>(std::forward<T>(t)))

>(std::get<Indices>(std::forward<T>(t)))...

);

}

};

// non-void return case...

template <typename Op, typename Tuple>

inline auto apply_tuple(Op&& op, Tuple&& t) ->

if_returns_nonvoid_case<

decltype(

apply_tuple_return_type(

std::forward<Op>(op), std::forward<Tuple>(t)

)

)

>

{

return

apply_tuple_impl<

make_seq_indices<0,tuple_size<Tuple>()>,

decltype(

apply_tuple_return_type(

std::forward<Op>(op), std::forward<Tuple>(t)

)

)

>::apply_tuple(std::forward<Op>(op),std::forward<Tuple>(t))

;

}

// void return case...

template <typename Op, typename Tuple>

inline auto apply_tuple(Op&& op, Tuple&& t) ->

if_returns_void_case<

decltype(

apply_tuple_return_type(

std::forward<Op>(op), std::forward<Tuple>(t)

)

)

>

{

apply_tuple_impl<

make_seq_indices<0,tuple_size<Tuple>()>,

decltype(

apply_tuple_return_type(

std::forward<Op>(op), std::forward<Tuple>(t)

)

)

>::apply_tuple(std::forward<Op>(op),std::forward<Tuple>(t));

}

Starting with `apply_tuple()`

, note the following:

- Two versions of
`apply_tuple()`

are needed: one for operations returning`void`

and one for those returning a type. The use of`enable_if`

allows the compiler to select the correct function based on`Op`

. `std::decay`

is used to strip`Tuple`

down to is base type so that the tuple's size can be determined.- With the size,
`make_seq_indices`

is invoked to generate the indices. `decltype`

is used to determine the operation's return type.

The purpose of `apply_tuple()`

is to forward everything to `apply_tuple_impl::apply_tuple()`

. This is needed since the indices **must** be a parameter pack. Unlike previous version, the indices and the return type are computed without using a template template type within `apply_tuple()`

. With `apply_tuple()`

setting things up, the definition of `apply_tuple_impl::apply_tuple()`

is straight-forward. The reader will note the code is identical to previous code since it still invokes `std::get<Indices>(std::forward<T>(t))`

. This is what has changed:

- The template arguments do not make use of any template template parameters. This allows rvalue template argument deduction and reference collapsing to take place. Consequently, this allows one to write one function for the two cases: the
`void`

return type and non-void return type. - What allowed Item 1 to be done was realizing that one wants to use
`decltype`

within the`std::forward`

template parameter to determine the type of each element instead of the tuple's template argument parameter pack. While this duplicates the get code twice, it permits the parameter pack expansion to work identically without explicitly using any template template parmeters. It also avoids any possibility of incorrect types between what is passed to the function and what is provided to`std::forward`

.

The choice of not directly using template template parameters is what enables this solution to eliminate four (4) function definitions (i.e., the lvalue overloads). As a bonus the solution's type safety is now robust since `std::forward`

's parameter type exactly matches what is provided to the function. This avoids the possibility of compiler "error novels" should somehow some of the types don't match up.

# Closing Comments

Overall, this solution is not pretty, but, it is straight-forward, maintainable (especially if some comments are added), and, best of all, its use by end-users is almost effortless. The end-user need not ever see the above as he/she would simply write code like this:

{

return a+b;

}

//...

std::tuple<int,double> some_tuple;

// ...

apply(add, 2, 34.2); // or

apply_tuple(add, some_tuple);

Such code can be easily written by newcomers and experienced C++ programmers alike!

Happy Coding! ðŸ™‚

Nice, sadly though, this only works with g++ 4.7 since 4.6 (which ships with Ubuntu, and as a rule I don't want people to have to compile their own compiler to compile my code) doesn't support `using` aliases yetâ€¦

The template aliases were only used to promote ease-of-reading and understanding. All of the template aliases can all be removed by substituting their definitions where they are used. The four-function solution however relies on compilers' C++11 support since decltype and move semantics are needed.

The GCC team appears to be planning to have v4.7 out soon. Additionally, all of the major C++ compilers are actively and seriously implementing C++11 in a short period of time as well. So my guess is everyone should be able to reap (at least most of if not all of) the benefits of C++11 at various points this year depending on the compiler being used.

This "apply tuple" serie was great. Didn't know before about template aliases and also about this helper function prototype trick to determine return type. That's really neat.

Still, I believe that your final version of apply_tuple() can be greatly simplified. Here is a couple of suggestions :

[1] I don't understand the necessity to have two paths, one for function that return void and one for function that return non-void.

The following code is legal :

void foo(){}

void goo()

{

return foo();

}

So you can remove completely the void path in apply_tuple and just do directly something like return op(std::get(tup)…);

[2] About this line :

op( std::forward< decltype(std::get(std::forward(t)))

>(std::get(std::forward(t)))… );

I think that you don't need to perfectly forward again the result of std::get. You can do this :

op( std::get(std::forward(t))… );

Because std::get already do the right thing : there is two overload of std::get, one for lvalue, one for rvalue :

// 20.4.2.6, element access:

template

typename tuple_element<I, tuple >::type& get(tuple&) noexcept;

template

typename tuple_element<I, tuple >::type&& get(tuple&&) noexcept;

[3] Another point, it maybe just a style issue but I prefer to pass the indices list as a parameter to a function apply_tuple_imp instead as a template parameter to a struct apply_tuple_imp, because there is so much less syntactic overhead this way.

So I finally came up with the following, compact implementation of apply_tuple. I believe it cover all cases. What do you think of it ?

template

struct tuple_indices {};

template

struct make_indices_imp;

template

struct make_indices_imp<Sp, tuple_indices, Ep>

{

using type = typename make_indices_imp<Sp+1, tuple_indices, Ep>::type;

};

template

struct make_indices_imp<Ep, tuple_indices, Ep>

{

using type = tuple_indices;

};

template

using make_tuple_indices = typename make_indices_imp<Sp, tuple_indices, Ep>::type;

template

using apply_tuple_indices = make_tuple_indices<std::tuple_size<typename std::decay::type>::value>;

template

auto apply_tuple_imp(Op&& op, Tuple&& t, tuple_indices)

-> decltype(std::forward(op)(std::get(std::forward(t))…))

{

return std::forward(op)(std::get(std::forward(t))…);

}

template

auto apply_tuple(Op&& op, Tuple&& t)

->decltype(apply_tuple_imp(std::forward(op), std::forward(t), apply_tuple_indices()))

{

return apply_tuple_imp(std::forward(op), std::forward(t), apply_tuple_indices());

}

double func_double(int i, double d)

{

return i + d;

}

void func_void(int i, double d)

{

std::cout << i + d << "\n";

}

void func_movable(std::string&& s)

{

}

int main()

{

std::tuple t(4, 5.0);

std::cout << apply_tuple(func_double, t) << "\n";

std::cout << apply_tuple([](int i, double d){return i + d;}, t) << "\n";

std::cout << apply_tuple(func_double, std::tuple(8, 4.0)) << "\n";

apply_tuple(func_void, t);

apply_tuple(func_void, std::tuple(8, 4.0));

apply_tuple(func_movable, std::forward_as_tuple("C++o"));

apply_tuple(func_movable, std::tuple("C++"));

std::tuple tmov("C++");

apply_tuple(func_movable, std::move(tmov));

}

Yes, absolutely your suggestions are all good and do simplify the code considerably! I should have noticed each of them myself, however, I was very busy when I wrote the last few posts so I am not surprised some simplifications were missed. (I only spent the time to ensure the code was correct and many of the simplications possible were done.) Certainly, I do revisit code from time-to-time to have fresh eyes to better see things in a new light (esp. with the newness of C++11 features as they get implemented in compilers) and I was taking a break from it for a few weeks. Your post has me looking at it a little sooner than I was planning!

Concerning point [1]: For anyone surprised about this point, know that in ISO C++03 (and in C++11) it states in 6.6.3 paragraph 3 that a void function can have a return statement whose expression is void (regardless of cv-qualifiers). Thus, it is legal code. While not very useful in non-template code, when using templates with functions/functors it is wonderful.

Concerning point [2]: When I wrote the code I felt that omitting the forward would be totally correct. I kept it in however since some "playing around" code had cv-qualifier type issues and I wanted no chance that I missed something in my blog post. I thought I would revisit it after a break to see if it could be removed. (And clearly it can be as std::get() is properly overloaded for l- and r-values.)

Concerning point [3]: It looks good. Unfortunately, your code had its < and > removed by WordPress' editor (sigh!) as the template code wasn't legal HTML. With respect to the indices, generally I try avoiding unnecessary function arguments that are never used –hence my use of a class. In this instance doing such makes the code simpler by eliminating the helper class entirely at no real cost (with anything better than -O0 with any decent C++ compiler) –so it works.

I've modified and tested my code concerning such and all is good! (No surprise!) I'll post an updated article very soon with the updated code so others can see it all neat and tidy.

Observations of the results…

1) Nicely, all of the std::enable_if guards are no longer needed. Clearly fewer symbols is better for the compiler (e.g., compile time, space, and ability to perform optimizations).

2) Nicely, all of the series of articles on this are conceptually the same concerning the big picture of how everything works –even though the specifics differ somewhat. Even the articles that are now obsoleted with the latest tweaks are useful in that they show how to use various template metaprogramming techniques –which perhaps this article series is not a half-bad example set to use for one learning such –even if I am a bit heavy with the code/text at times?

3) Another thing I like is that it shows how things are developed and refined over time. IMHO one learns a lot from studying how solutions are developed and especially why some solutions are less good than other solutions. For example, this is what I've always liked about Herb Sutter's "Exceptional C++" and "More Exceptional C++" books: he asks, presents, and explains an entire gamut of issues concerning important topics –not just a final "best/decent" solution.

Closing comments…

Now only 2 apply_tuple() functions are required, 1 apply_tuple() function, the two function prototypes (with no definitions), plus the make_seq_indices (or whatever one wants to generate the indices). The rest of the code is simply some template aliases and constexpr functions that make it easier to read the code. Awesome!!

I'll post this soon on my blog.