Assume a sequence of variadic parameter types is to be generated according to a index sequence, i.e, given a tuple
using Tuple = std::tuple<int, float, bool>;
and a function signature as following:
template <std::size_t ...Is>
void func(std::index_sequence<Is...>, std::tuple_element_t<Is, Tuple>...) {}
a invocation like func(std::make_index_sequence<2>(), 2, 1.0) would compile without problem.
However, if we were to compute the size of std::index_sequence according to another type, and therefore place std::index_sequence at the end of parameter list with a default argument, just like this:
template <typename T, std::size_t ...Is>
void func(T, std::tuple_element_t<Is, Tuple>..., std::index_sequence<Is...> = std::make_index_sequence<some_computation_v<T>>()) {}
The compilation of g++ and clang++ would succeed if and only if the size of std::index_sequence is 0, that is, for following signature:
template <std::size_t... Is>
void func(std::tuple_element_t<Is, Tuple>..., std::index_sequence<Is...> = std::make_index_sequence<2>()) {}
func(2, 1.0) or func(2, 1.0, std::make_index_sequence<2>()) would result in error:
main.cpp:34:6: note: template argument deduction/substitution failed:
main.cpp:43:16: note: mismatched types ‘std::integer_sequence<long unsigned int, _Idx ...>’ and ‘int’
func(2, 1.0);
This prevents me from restricting the types of variadic template with a key type T, by mapping T to a tuple of parameter types and expand it using std::index_sequence.
Is there any way to resolve this error or to meet the needs mentioned above?
Write a "is prefix of types" trait. Use it in a requires clause.
template<class T0>
struct is_tuple_prefix_helper{
template<class T1>
static std::false_type test(T1 const&);
};
template<template<class...>class Z, class...T0s>
struct is_tuple_prefix_helper<Z<T0s...>>{
template<class T1>
static std::false_type test(T1 const&);
template<class...T1s>
static std::true_type test(Z<T0s...,T1s...> const&);
};
template<class T0, class T1>
constexpr bool is_tuple_prefix_v=decltype( is_tuple_prefix_helper<T0>::test(std::declval<T1>()) )::value;
Then
using tup=std::tuple<int,char,double>
template<class...Ts> requires( is_tuple_prefix_v<std::tuple<Ts...>, tup> )
void restricted_func(Ts const&...);
should work.
The problem you have is that you are asking to invert a compile time type mapping. C++ will not invert most compile time type mappings for you; doing so in general is HALT-hard, so C++ does not try. It will do basic pattern matching, that is all.
This allows you to write a Turing-complete inversion or test, but you have to write it.
This is c++20 based. An earlier version of C++ would instead use SFINAE and other less elegant machinery to do the same thing. In c++14:
template<class...Ts,
std::enable_if_t< is_tuple_prefix_v<std::tuple<Ts...>, tup>, bool > =true
>
void restricted_func(Ts const&...);
How that exactly works is crazy black magic, honestly. There is a reason they added requires in c++20.
In std::tuple_element<Is, Tuple>::type, Is is non deducible. default function argument doesn't participate in the deduction or parameter's types, so entire pack is empty.
You might still write helper function to have expected API order:
template <std::size_t ...Is>
void func_impl(std::index_sequence<Is...>, std::tuple_element_t<Is, Tuple>...)
{
// ...
}
template <typename T, typename ... Ts>
auto func(T, Ts&&... args)
// possibly decltype return type for SFINAE
{
return func_impl(std::make_index_sequence<some_computation_v<T>>(),
std::forward<Ts>(args)...);
}
So I'm trying to figure out how this works: C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args?
The piece of black magic I do not understand is this code fragment:
f(std::get<N>(std::forward<Tuple>(t))...)
it's the expression inside f that I don't understand.
I understand that the expression somehow unpacks/expands what's inside t into a list of arguments. But could someone care to explain how this is done? When I look at the definition of std::get (http://en.cppreference.com/w/cpp/utility/tuple/get), I don't see how N fits in...? As far as I can tell, N is a sequence of integers.
Based on what I can observe, I'm assuming that expressions in the form E<X>... where X is the sequence of types X1. X2, ... Xn, the expression will be expanded as E<X1>, E<X2> ... E<Xn>. Is this how it works?
Edit: In this case N is not a sequence of types, but integers. But I'm guessing this language construct applies to both types and values.
I think that #Xeo's comment summed it up well. From 14.5.3 of the C++11 standard:
A pack expansion consists of a pattern and an ellipsis, the
instantiation of which produces zero or more instantiations of the
pattern in a list.
In your case, by the time you finish with the recursive template instantiation and end up in the partial specialization, you have
f(std::get<N>(std::forward<Tuple>(t))...);
...where N is parameter pack of four ints (0, 1, 2, and 3). From the standardese above, the pattern here is
std::get<N>(std::forward<Tuple>(t))
The application of the ... ellipsis to the above pattern causes it to be expanded into four instantiations in list form, i.e.
f(std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t));
The fundamental ingredient to expanding the std::tuple<T...> is actually omitted from the code: you need to obtain a a second parameter back: in addition to the list of types of the std::tuple<...> you need a parameter pack with indices 0, 1, ..., n. Once you have these two parameters packs, you can expand them in tandem:
template <typename F, typename... T, int... N>
void call_impl(F&& fun, std::tuple<T...>&& t) {
fun(std::get<N>(t)...);
}
The real magic lies in conjuring up the second parameter pack when you just have a std::tuple<T...>. It takes a bit of template programming. Here is an approach to create the list of indices:
template <int... Indices> struct indices;
template <> struct indices<-1> { typedef indices<> type; };
template <int... Indices>
struct indices<0, Indices...>
{
typedef indices<0, Indices...> type;
};
template <int Index, int... Indices>
struct indices<Index, Indices...>
{
typedef typename indices<Index - 1, Index, Indices...>::type type;
};
template <typename T>
typename indices<std::tuple_size<T>::value - 1>::type const*
make_indices()
{
return 0;
}
So, if you have a function template, let's call it call() which takes a function object and a std::tuple<T...> with the arguments to the function. An easy approach is to rewrite the call_impl() mentioned above to deal with deducing the indices:
template <typename F, typename Tuple, int... N>
void call_impl(F&& fun, Tuple&& t, indices<Indices...> const*)
{
fun(std::get<N>(t)...);
}
template <typename F, typename Tuple>
void call(F&& fun, Tuple&& t)
{
call_imle(std::forward<F>(fun), std::forward<Tuple>(t), make_indices<Tuple>());
}
What this code doesn't really extend is the correct use of std::forward<...>() with the various std::tuple<...> elements when calling the function. Just using std::forward<Tuple>(t) does not work because it possibly moves the entire std::tuple<...> rather than moving the elements. I think something like a suitable element-wise move of a std::tuple<...> can be done but I haven't done it, yet.
I'm trying to implement a function similar to std::transform algorithm but instead of taking the output iterator by an argument I want to create and return a container with transformed input elements.
Let's say that it's named transform_container and takes two arguments: container and functor. It should return the same container type but possibly parametrized by a different element type (the Functor can return element of different type).
I'd like to use my function as in the example below:
std::vector<int> vi{ 1, 2, 3, 4, 5 };
auto vs = transform_container(vi, [] (int i) { return std::to_string(i); });
//vs will be std::vector<std::string>
assert(vs == std::vector<std::string>({"1", "2", "3", "4", "5"}));
std::set<int> si{ 5, 10, 15 };
auto sd = transform_container(si, [] (int i) { return i / 2.; });
//sd will be of type std::set<double>
assert(sd == std::set<double>({5/2., 10/2., 15/2.}));
I was able two write two functions — one for std::set and one for std::vector — that seem to work properly. They are identical, except of the container typename. Their code is listed below.
template<typename T, typename Functor>
auto transform_container(const std::vector<T> &v, Functor &&f) -> std::vector<decltype(f(*v.begin()))>
{
std::vector<decltype(f(*v.begin()))> ret;
std::transform(std::begin(v), std::end(v), std::inserter(ret, ret.end()), f);
return ret;
}
template<typename T, typename Functor>
auto transform_container(const std::set<T> &v, Functor &&f) -> std::set<decltype(f(*v.begin()))>
{
std::set<decltype(f(*v.begin()))> ret;
std::transform(std::begin(v), std::end(v), std::inserter(ret, ret.end()), f);
return ret;
}
However, when I attempted to merge them into a single general function that works with any container, I encountered numerous issues. The set and vector are class templates, so my function template must take a template template parameter. Moreover, set and vector templates have a different number of type parameters that needs to be properly adjusted.
What is the best way to generalize the two function templates above into a function that works with any compatible container type?
Simplest cases: matching container types
For the simple case where the input type matches the output type (which I've since realized is not what you're asking about) go one level higher. Instead of specifying the type T that your container uses, and trying to specialize on a vector<T>, etc., just specify the type of the container itself:
template <typename Container, typename Functor>
Container transform_container(const Container& c, Functor &&f)
{
Container ret;
std::transform(std::begin(c), std::end(c), std::inserter(ret, std::end(ret)), f);
return ret;
}
More complexity: compatible value types
Since you want to try to change the item type stored by the container, you'll need to use a template template parameter, and modify the T to that which the returned container uses.
template <
template <typename T, typename... Ts> class Container,
typename Functor,
typename T, // <-- This is the one we'll override in the return container
typename U = std::result_of<Functor(T)>::type,
typename... Ts
>
Container<U, Ts...> transform_container(const Container<T, Ts...>& c, Functor &&f)
{
Container<U, Ts...> ret;
std::transform(std::begin(c), std::end(c), std::inserter(ret, std::end(ret)), f);
return ret;
}
What of incompatible value types?
This only gets us partway there. It works fine with a transform from signed to unsigned but, when resolving with T=int and U=std::string, and handling sets, it tries to instantiate std::set<std::string, std::less<int>, ...> and thus doesn't compile.
To fix this, we want to take an arbitrary set of parameters and replace instances of T with U, even if they are the parameters to other template parameters. Thus std::set<int, std::less<int>> should become std::set<std::string, std::less<std::string>>, and so forth. This involves some custom template meta programming, as suggested by other answers.
Template metaprogramming to the rescue
Let's create a template, name it replace_type, and have it convert T to U, and K<T> to K<U>. First let's handle the general case. If it's not a templated type, and it doesn't match T, its type shall remain K:
template <typename K, typename ...>
struct replace_type { using type = K; };
Then a specialization. If it's not a templated type, and it does match T, its type shall become U:
template <typename T, typename U>
struct replace_type<T, T, U> { using type = U; };
And finally a recursive step to handle parameters to templated types. For each type in a templated type's parameters, replace the types accordingly:
template <template <typename... Ks> class K, typename T, typename U, typename... Ks>
struct replace_type<K<Ks...>, T, U>
{
using type = K<typename replace_type<Ks, T, U>::type ...>;
};
And finally update transform_container to use replace_type:
template <
template <typename T, typename... Ts> class Container,
typename Functor,
typename T,
typename U = typename std::result_of<Functor(T)>::type,
typename... Ts,
typename Result = typename replace_type<Container<T, Ts...>, T, U>::type
>
Result transform_container(const Container<T, Ts...>& c, Functor &&f)
{
Result ret;
std::transform(std::begin(c), std::end(c), std::inserter(ret, std::end(ret)), f);
return ret;
}
Is this complete?
The problem with this approach is it is not necessarily safe. If you're converting from Container<MyCustomType> to Container<SomethingElse>, it's likely fine. But when converting from Container<builtin_type> to Container<SomethingElse> it's plausible that another template parameter shouldn't be converted from builtin_type to SomethingElse. Furthermore, alternate containers like std::map or std::array bring more problems to the party.
Handling std::map and std::unordered_map isn't too bad. The primary problem is that replace_type needs to replace more types. Not only is there a T -> U replacement, but also a std::pair<T, T2> -> std::pair<U, U2> replacement. This increases the level of concern for unwanted type replacements as there's more than a single type in flight. That said, here's what I found to work; note that in testing I needed to specify the return type of the lambda function that transformed my map's pairs:
// map-like classes are harder. You have to replace both the key and the key-value pair types
// Give a base case replacing a pair type to resolve ambiguities introduced below
template <typename T1, typename T2, typename U1, typename U2>
struct replace_type<std::pair<T1, T2>, std::pair<T1, T2>, std::pair<U1, U2>>
{
using type = std::pair<U1, U2>;
};
// Now the extended case that replaces T1->U1 and pair<T1,T2> -> pair<T2,U2>
template <template <typename...> class K, typename T1, typename T2, typename U1, typename U2, typename... Ks>
struct replace_type<K<T1, T2, Ks...>, std::pair<const T1, T2>, std::pair<const U1, U2>>
{
using type = K<U1, U2,
typename replace_type<
typename replace_type<Ks, T1, U1>::type,
std::pair<const T1, T2>,
std::pair<const U1, U2>
>::type ...
>;
};
What about std::array?
Handling std::array adds to the pain, as its template parameters cannot be deduced in the template above. As Jarod42 notes, this is due to its parameters including values instead of just types. I've gotten partway by adding specializations and introducing a helper contained_type that extracts T for me (side note, per Constructor this is better written as the much simpler typename Container::value_type and works for all types I've discussed here). Even without the std::array specializations this allows me to simplify my transform_container template to the following (this may be a win even without support for std::array):
template <typename T, size_t N, typename U>
struct replace_type<std::array<T, N>, T, U> { using type = std::array<U, N>; };
// contained_type<C>::type is T when C is vector<T, ...>, set<T, ...>, or std::array<T, N>.
// This is better written as typename C::value_type, but may be necessary for bad containers
template <typename T, typename...>
struct contained_type { };
template <template <typename ... Cs> class C, typename T, typename... Ts>
struct contained_type<C<T, Ts...>> { using type = T; };
template <typename T, size_t N>
struct contained_type<std::array<T, N>> { using type = T; };
template <
typename Container,
typename Functor,
typename T = typename contained_type<Container>::type,
typename U = typename std::result_of<Functor(T)>::type,
typename Result = typename replace_type<Container, T, U>::type
>
Result transform_container(const Container& c, Functor &&f)
{
// as above
}
However the current implementation of transform_container uses std::inserter which does not work with std::array. While it's possible to make more specializations, I'm going to leave this as a template soup exercise for an interested reader. I would personally choose to live without support for std::array in most cases.
View the cumulative live example
Full disclosure: while this approach was influenced by Ali's quoting of Kerrek SB's answer, I didn't manage to get that to work in Visual Studio 2013, so I built the above alternative myself. Many thanks to parts of Kerrek SB's original answer are still necessary, as well as to prodding and encouragement from Constructor and Jarod42.
Some remarks
The following method allows to transform containers of any type from the standard library (there is a problem with std::array, see below). The only requirement for the container is that it should use default std::allocator classes, std::less, std::equal_to and std::hash function objects. So we have 3 groups of containers from the standard library:
Containers with one non-default template type parameter (type of value):
std::vector, std::deque, std::list, std::forward_list, [std::valarray]
std::queue, std::priority_queue, std::stack
std::set, std::unordered_set
Containers with two non-default template type parameters (type of key and type of value):
std::map, std::multi_map, std::unordered_map, std::unordered_multimap
Container with two non-default parameters: type parameter (type of value) and non-type parameter (size):
std::array
Implementation
convert_container helper class convert types of known input container type (InputContainer) and output value type (OutputType) to the type of the output container(typename convert_container<InputContainer, Output>::type):
template <class InputContainer, class OutputType>
struct convert_container;
// conversion for the first group of standard containers
template <template <class...> class C, class IT, class OT>
struct convert_container<C<IT>, OT>
{
using type = C<OT>;
};
// conversion for the second group of standard containers
template <template <class...> class C, class IK, class IT, class OK, class OT>
struct convert_container<C<IK, IT>, std::pair<OK, OT>>
{
using type = C<OK, OT>;
};
// conversion for the third group of standard containers
template
<
template <class, std::size_t> class C, std::size_t N, class IT, class OT
>
struct convert_container<C<IT, N>, OT>
{
using type = C<OT, N>;
};
template <typename C, typename T>
using convert_container_t = typename convert_container<C, T>::type;
transform_container function implementation:
template
<
class InputContainer,
class Functor,
class InputType = typename InputContainer::value_type,
class OutputType = typename std::result_of<Functor(InputType)>::type,
class OutputContainer = convert_container_t<InputContainer, OutputType>
>
OutputContainer transform_container(const InputContainer& ic, Functor f)
{
OutputContainer oc;
std::transform(std::begin(ic), std::end(ic), std::inserter(oc, oc.end()), f);
return oc;
}
Example of use
See live example with the following conversions:
std::vector<int> -> std::vector<std::string>,
std::set<int> -> std::set<double>,
std::map<int, char> -> std::map<char, int>.
Problems
std::array<int, 3> -> std::array<double, 3> conversion doesn't compile because std::array haven't insert method which is needed due to std::inserter). transform_container function shouldn't also work for this reason with the following containers: std::forward_list, std::queue, std::priority_queue, std::stack, [std::valarray].
Doing this in general is going to be pretty hard.
First, consider std::vector<T, Allocator=std::allocator<T>>, and let's say your functor transforms T->U. Not only do we have to map the first type argument, but really we ought to use Allocator<T>::rebind<U> to get the second. This means we need to know the second argument is an allocator in the first place ... or we need some machinery to check it has a rebind member template and use it.
Next, consider std::array<T, N>. Here we need to know the second argument should be copied literally to our std::array<U, N>. Perhaps we can take non-type parameters without change, rebind type parameters which have a rebind member template, and replace literal T with U?
Now, std::map<Key, T, Compare=std::less<Key>, Allocator=std::allocator<std::pair<Key,T>>>. We should take Key without change, replace T with U, take Compare without change and rebind Allocator to std::allocator<std::pair<Key, U>>. That's a little more complicated.
So ... can you live without any of that flexibility? Are you happy to ignore associative containers and assume the default allocator is ok for your transformed output container?
The major difficulty is to somehow get the container type Container from Conainer<T>. I have shamelessly stolen the code from template metaprogramming: (trait for?) dissecting a specified template into types T<T2,T3 N,T4, ...>, in particular, Kerrek SB's answer (the accepted answer), as I am not familiar with template metaprogramming.
#include <algorithm>
#include <cassert>
#include <type_traits>
// stolen from Kerrek SB's answer
template <typename T, typename ...>
struct tmpl_rebind {
typedef T type;
};
template <template <typename ...> class Tmpl, typename ...T, typename ...Args>
struct tmpl_rebind<Tmpl<T...>, Args...> {
typedef Tmpl<Args...> type;
};
// end of stolen code
template <typename Container,
typename Func,
typename TargetType = typename std::result_of<Func(typename Container::value_type)>::type,
typename NewContainer = typename tmpl_rebind<Container, TargetType>::type >
NewContainer convert(const Container& c, Func f) {
NewContainer nc;
std::transform(std::begin(c), std::end(c), std::inserter(nc, std::end(nc)), f);
return nc;
}
int main() {
std::vector<int> vi{ 1, 2, 3, 4, 5 };
auto vs = convert(vi, [] (int i) { return std::to_string(i); });
assert( vs == std::vector<std::string>( {"1", "2", "3", "4", "5"} ) );
return 0;
}
I have tested this code with gcc 4.7.2 and clang 3.5 and works as expected.
As Yakk points out, there are quite a few caveats with this code though: "... should your rebind replace all arguments, or just the first one? Uncertain. Should it recursively replace T0 with T1 in later arguments? Ie std::map<T0, std::less<T0>> -> std::map<T1, std::less<T1>>?" I also see traps with the above code (e.g. how to deal with different allocators, see also Useless' answer).
Nevertheless, I believe the above code is already useful for simple use cases. If we were writing a utility function to be submitted to boost, then I would be more motivated to investigate these issues further. But there is already an accepted answer so I consider the case closed.
Many thanks to Constructor, dyp and Yakk for pointing out my mistakes / missed opportunities for improvements.
I wrote a blog post to solve a similar problem recently. Using templates and the iterator interface was the route I chose to follow.
for_each:
To cut down on the amount of boilerplate, we're going to create a using clause that allows us to grab the type contained within an iterator:
template <typename IteratorType>
using ItemType = typename std::iterator_traits<typename IteratorType::iterator>::value_type;
With that in place, we can implement a helper function for_each like so:
template <typename IteratorType>
void for_each(IteratorType &items, std::function<void(ItemType<IteratorType> const &item)> forEachCb)
{
for (typename IteratorType::iterator ptr = items.begin(); ptr != items.end(); ++ptr)
forEachCb(*ptr);
}
transform_container:
Finally transform_container, could be implemented like so:
template <typename IteratorType, typename ReturnType>
ReturnType transform_container(IteratorType &items, std::function<ItemType<ReturnType>(ItemType<IteratorType> const &item)> mapCb)
{
ReturnType mappedIterator;
for_each<IteratorType>(items, [&mappedIterator, &mapCb](auto &item) { mappedIterator.insert(mappedIterator.end(), mapCb(item)); });
return mappedIterator;
}
Which will allow us to call your two examples in the following way:
std::vector<int> vi{ 1, 2, 3, 4, 5 };
auto vs = transform_container<std::vector<int>, std::vector<std::string>>(vi, [](int i){return std::to_string(i);});
assert(vs == std::vector<std::string>({"1", "2", "3", "4", "5"}));
std::set<int> si{ 5, 10, 15 };
auto sd = transform_container<std::set<int>, std::set<double>>(si, [] (int i) { return i / 2.; });
assert(sd == std::set<double>({5/2., 10/2., 15/2.}));
My blog post also goes into a little more detail if that's helpful.
I want to write a constexpr function, that reduces a given std::array with a binary operation. I.e. a function which implements
template <typename T, std::size_t N>
reduce(std::array<T, N>, binary_function);
To keep things simple I want to start with addition. E.g.
sum(std::array<int, 5>{{1,2,3,4,5}}); // returns 15.
What I got so far.
I use the usual indexing trick to index array elements. I.e. generate a int sequence, that can be used for indexing with parameter list-expansion.
template <int... Is>
struct seq {};
template <int I, int... Is>
struct gen_seq : gen_seq<I - 1, I - 1, Is...> {};
template <int... Is>
struct gen_seq<0, Is...> : seq<Is...> {}; // gen_seq<4> --> seq<0, 1, 2, 3>
The sum function is then defined through variadic template recursion.
// The edge-condition: array of one element.
template <typename T>
constexpr T sum(std::array<T, 1> arr, decltype(gen_seq<0>{})) {
return std::get<0>(arr);
}
// The recursion.
template <typename T, std::size_t N, int... Is>
constexpr auto sum(std::array<T, N> arr, seq<Is...>) -> decltype(T() + T()) {
return sum(std::array<T, N - 1>{ { std::get<Is>(arr)... } },
gen_seq<N - 2>()) +
std::get<N - 1>(arr);
}
// The interface - hides the indexing trick.
template <typename T, std::size_t N>
constexpr auto sum(std::array<T, N> arr)
-> decltype(sum(arr, gen_seq<N - 1>{})) {
return sum(arr, gen_seq<N - 1>{});
}
Here you can see it in action.
Questions
This implementation works. However, I do have a few questions at this stage.
Is there any way, I can add perfect-forward to this function? And does that even make sense? Or should I declare those arrays const-references?
The assumption so far is, that the return-type of the reduction is decltype(T()+T()). I.e. what you get when you add two elements. While this should be true for addition in most cases, it might no longer be true for a general reduction. Is there a way, of getting the type of a[0] + (a[1] + (a[2] + ... ) )? I tried something like this, but I don't know how I can produce a template parameter list of <T, T, T, ...>.
My answer is based on my own implementation of such staff.
I prefer the general reduce (or fold, or accumulate) function to operate directly on elements as its own function arguments rather than being within a container like std::array. This way, instead of constructing a new array in every recursion, elements are passed as arguments and I guess the whole operation is easier for the compiler to inline. Plus it's more flexible, e.g. could be used directly or on the elements of a std::tuple. The general code is here. I repeat here the main function:
template <typename F>
struct val_fold
{
// base case: one argument
template <typename A>
INLINE constexpr copy <A>
operator()(A&& a) const { return fwd<A>(a); }
// general recursion
template <typename A, typename... An>
INLINE constexpr copy <common <A, An...> >
operator()(A&& a, An&&... an) const
{
return F()(fwd<A>(a), operator()(fwd<An>(an)...));
}
};
I am sorry this is full of my own definitions, so here is some help: F is the function object defining the binary operation. copy is my generalization of std::decay that recurses within arrays and tuples. fwd is just a shortcut for std::forward. Similarly, common is just a shortcut for std::common_type but intended for a similar generalization (in general, each operation may yield an expression template for lazy evaluation and here we are forcing evaluation).
How would you define sum using the above? First define the function object,
struct sum_fun
{
template <typename A, typename B>
INLINE constexpr copy <common <A, B> >
operator()(A&& a, B&& b) const { return fwd<A>(a) + fwd<B>(b); }
};
then just
using val_sum = val_fold<sum_fun>;
How would you call this when starting with an std::array? Well, once you've got your Is..., all you need is
val_sum()(std::get<Is>(arr)...);
which you may wrap within your own interface. Note that in C++14, std::array::operator[] is constexpr, so this would just be
val_sum()(arr[Is]...);
Now, to your questions:
1) Forwarding: Yes, std::get is forwarding array elements into val_sum, which is recursively forwarding everything to itself. So all that remains is your own interface to forward the input array, e.g.
template <typename A, /* enable_if to only allow arrays here */>
constexpr auto sum(A&& a) -> /* return type here */
{
return sum(std::forward<A>(a), gen_seq_array<A>{});
}
and so on, where gen_seq_array would take the raw type of A (std::remove_ref, std::remove_cv etc.), deduce N, and call gen_seq<N>{}. Forwarding makes sense if array elements have move semantics. It should be everywhere, e.g. the call of val_sum above would be something like
val_sum()(std::get<Is>(std::forward<A>(a))...);
2) Return type: As you have seen, I am using std::common_type as the return type, which should do for sum and most common arithmetic operations. This is already variadic. If you'd like your own type function, it's easy to make a variadic out of a binary type function, using template recursion.
My own version of common is here. It's a bit more involved, but it is still a recursive template containing some decltype to do the actual work.
In any case, this is more general than what you need, because it's defined for an arbitrary number of any given types. You only have one type T in your array, so what you have should be enough.
So I'm trying to figure out how this works: C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args?
The piece of black magic I do not understand is this code fragment:
f(std::get<N>(std::forward<Tuple>(t))...)
it's the expression inside f that I don't understand.
I understand that the expression somehow unpacks/expands what's inside t into a list of arguments. But could someone care to explain how this is done? When I look at the definition of std::get (http://en.cppreference.com/w/cpp/utility/tuple/get), I don't see how N fits in...? As far as I can tell, N is a sequence of integers.
Based on what I can observe, I'm assuming that expressions in the form E<X>... where X is the sequence of types X1. X2, ... Xn, the expression will be expanded as E<X1>, E<X2> ... E<Xn>. Is this how it works?
Edit: In this case N is not a sequence of types, but integers. But I'm guessing this language construct applies to both types and values.
I think that #Xeo's comment summed it up well. From 14.5.3 of the C++11 standard:
A pack expansion consists of a pattern and an ellipsis, the
instantiation of which produces zero or more instantiations of the
pattern in a list.
In your case, by the time you finish with the recursive template instantiation and end up in the partial specialization, you have
f(std::get<N>(std::forward<Tuple>(t))...);
...where N is parameter pack of four ints (0, 1, 2, and 3). From the standardese above, the pattern here is
std::get<N>(std::forward<Tuple>(t))
The application of the ... ellipsis to the above pattern causes it to be expanded into four instantiations in list form, i.e.
f(std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t));
The fundamental ingredient to expanding the std::tuple<T...> is actually omitted from the code: you need to obtain a a second parameter back: in addition to the list of types of the std::tuple<...> you need a parameter pack with indices 0, 1, ..., n. Once you have these two parameters packs, you can expand them in tandem:
template <typename F, typename... T, int... N>
void call_impl(F&& fun, std::tuple<T...>&& t) {
fun(std::get<N>(t)...);
}
The real magic lies in conjuring up the second parameter pack when you just have a std::tuple<T...>. It takes a bit of template programming. Here is an approach to create the list of indices:
template <int... Indices> struct indices;
template <> struct indices<-1> { typedef indices<> type; };
template <int... Indices>
struct indices<0, Indices...>
{
typedef indices<0, Indices...> type;
};
template <int Index, int... Indices>
struct indices<Index, Indices...>
{
typedef typename indices<Index - 1, Index, Indices...>::type type;
};
template <typename T>
typename indices<std::tuple_size<T>::value - 1>::type const*
make_indices()
{
return 0;
}
So, if you have a function template, let's call it call() which takes a function object and a std::tuple<T...> with the arguments to the function. An easy approach is to rewrite the call_impl() mentioned above to deal with deducing the indices:
template <typename F, typename Tuple, int... N>
void call_impl(F&& fun, Tuple&& t, indices<Indices...> const*)
{
fun(std::get<N>(t)...);
}
template <typename F, typename Tuple>
void call(F&& fun, Tuple&& t)
{
call_imle(std::forward<F>(fun), std::forward<Tuple>(t), make_indices<Tuple>());
}
What this code doesn't really extend is the correct use of std::forward<...>() with the various std::tuple<...> elements when calling the function. Just using std::forward<Tuple>(t) does not work because it possibly moves the entire std::tuple<...> rather than moving the elements. I think something like a suitable element-wise move of a std::tuple<...> can be done but I haven't done it, yet.