I am quite new to TMP world though I can easily understand the code but have problem writing new. I was given below question which I couldn't solve. Can someone help me understand how could I have done this.
Below is the description of the question
template<int... Xs> struct Vector;
It can be used like this:
Vector<1,2,3>
We want to write a function that takes multiple vectors, and zips then *.i.e. given input
Vector<1,2,3>, Vector<2,3,4>, Vector<3,4,5>
produce:
Vector<6,24,60>
A common way to implement this kind of computation statically is with a metafunction
template <typename... Vectors>
struct zip
{
using type = XXXX;
}
where XXXX is the logic of the zip. We could verify like so:
static_assert(
std::is_same<
zip<Vector<1, 2, 3>, Vector<2, 3, 4>, Vector<3, 4, 5>>::type,
Vector<6, 24, 60>>::value);
I would like to know, how to complete this logic, Thanks.
Here's a simple way to implement this zip metafunction in c++14 using partial template specializations:
template <int...> struct Vector;
template <typename...>
struct zip;
template <int... Is>
struct zip<Vector<Is...>> {
using type = Vector<Is...>;
};
template <int... Is, int... Js, typename... Vectors>
struct zip<Vector<Is...>, Vector<Js...>, Vectors...> {
using type = typename zip<Vector<(Is * Js)...>, Vectors...>::type;
};
Godbolt.org
You have chosen a rather non-trivial problem as your first attempt at template metaprogramming. Anyway, here's my take:
template<int... Xs> struct Vector;
template <int... Xs>
constexpr std::size_t vectorSize(Vector<Xs...>*) {
return sizeof...(Xs);
}
template <typename V>
constexpr std::size_t vectorSize() {
return vectorSize(static_cast<V*>(nullptr));
}
template <std::size_t I, int... Xs>
constexpr int getVal(Vector<Xs...>*) {
return std::get<I>(std::make_tuple(Xs...));
}
template <std::size_t I, typename V>
constexpr int getVal() {
return getVal<I>(static_cast<V*>(nullptr));
}
template <std::size_t I, typename... Vs>
constexpr int makeProd() {
return (getVal<I, Vs>() * ...);
}
template <typename... Vs, std::size_t... Is>
constexpr auto zipHelper(std::index_sequence<Is...>)
-> Vector<makeProd<Is, Vs...>()...>;
template <typename... Vs>
struct zip
{
static constexpr std::size_t size =
vectorSize<std::tuple_element_t<0, std::tuple<Vs...>>>();
static_assert(((vectorSize<Vs>() == size) && ...));
using type = decltype(zipHelper<Vs...>(std::make_index_sequence<size>{}));
};
Demo
Related
I'm currently looking for a solution to give a templated classes’ constructor and function a fixed template according number of arguments N. My template is of the form template<typename T, unsigned int N>. The idea is that the following will work:
MyClass<int, 4> object(1, 2, 3, 4);
While the following should fail (and so on):
MyClass<int, 4> object(1, 2, 3);
MyClass<int, 4> object(1, 2, 3, 4, 5);
I'm thinking about something like MyClass(T arg1, ..., T argN){...} but automatically generated. I only found solutions on how to give a template one or many arguments. But nothing on fixed count.
I Hope somebody can help me. Thank You in advance!
You might use intermediate type and using std::index_sequence:
template <typename T, std::size_t>
using always_t = T;
template <typename T, typename Seq> struct MyClassImpl;
template <typename T, std::size_t ... Is>
struct MyClassImpl<T, std::index_sequence<Is...>>
{
MyClassImpl(always_t<T, Is>...);
};
template <typename T, std::size_t N>
using MyClass = MyClassImpl<T, std::make_index_sequence<N>>;
Demo.
Or, similarly, with simpler MyClassImpl, and complexity is moved in the alias:
template <typename ...Ts>
struct MyClassImpl
{
MyClassImpl(Ts... args);
};
template <typename T, std::size_t>
using always_t = T;
template <typename T, typename Seq>
struct MyClassAlias;
template <typename T, std::size_t... Is>
struct MyClassAlias<T, std::index_sequence<Is...>>
{
using type = MyClassImpl<always_t<T, Is>...>;
};
template <typename T, std::size_t N>
using MyClass = typename MyClassAlias<T, std::make_index_sequence<N>>::type;
Demo
You can add a constraint to the overload, such as
template <typename T, std::size_t N>
struct MyClass {
// pre-C++20
template <typename... Args, std::enable_if_t<sizeof...(Args) == N, int> = 0>
MyClass(Args&&... args) { /* ... */ }
// or alternatively, post-C++20,
template <typename... Args>
requires (sizeof...(Args) == N)
MyClass(Args&&... args) { /* ... */ }
};
Demo
Note that in the case N == 1 then in a couple of cases these templates will be preferred over the automatically generated copy constructor. If this is a potential issue then you will need to further constrain the templates to prevent this case. Here is an example of how you might do so.
If you don't need to use SFINAE to discern between other constructors, you could instead use static_assert as well:
template <typename... Args>
MyClass(Args&&... args) {
static_assert(sizeof...(Args) == N);
// ...
}
It is possible to use template parameters pack as follows:
template <int T1, int... Ts>
struct Test {
static constexpr int sizes[] = {Ts...};
};
template <int T1, int... Ts>
constexpr int Test<T1, Ts...>::sizes[];
However, as it is detailed here, the template parameter pack must be the last template parameter. Hence, we cannot have a code such as this:
template <int T1, int... Ts, int Tn>
struct Test {
static constexpr int sizes[] = {Ts...};
Foo<Ts...> foo;
};
template <int T1, int... Ts, int Tn>
constexpr int Test<T1, Ts..., Tn>::sizes[];
In many cases, we need to have access to the last element of a set of template parameters. My question is, what's the best practice for realizing the above code?
Edit:
This is not duplicate of this question. I am trying to get everything except the last parameter (not the last parameter itself), since I need to define Foo as follows:
Foo<Ts...> foo;
You could go with the standard method of using std::index_sequence
template<template<auto...> typename Tmp, size_t... Is, typename... Args>
constexpr auto take_as(std::index_sequence<Is...>, Args...)
{
using Tup = std::tuple<Args...>;
return Tmp<std::tuple_element_t<Is, Tup>{}...>{};
}
template<auto... Vals>
struct except_last
{
template<template<auto...> typename Tmp>
using as = decltype(take_as<Tmp>(std::make_index_sequence<sizeof...(Vals) - 1>{},
std::integral_constant<decltype(Vals), Vals>{}...));
};
Which you use as
using F = except_last<1, 2, 3, 4>::as<Foo>; // F is Foo<1, 2, 3>
This is both easier to implement and read, but you potentially get O(n) instantiation depth. If you are obsessed with efficiency, you could do O(1) instantiation depth by abusing fold expressions
template<typename T>
struct tag
{
using type = T;
};
template<typename F, typename... Ts>
using fold_t = decltype((F{} + ... + tag<Ts>{}));
template<size_t N, typename... Ts>
struct take
{
template<typename T>
auto operator+(tag<T>) -> take<N - 1, Ts..., T>;
};
template<typename... Ts>
struct take<0, Ts...>
{
template<template<auto...> typename Tmp>
using as = Tmp<Ts{}...>;
template<typename T>
auto operator+(tag<T>) -> take<0, Ts...>;
};
template<auto... Vals>
struct except_last
{
template<template<auto...> typename Tmp>
using as = fold_t<take<sizeof...(Vals) - 1>,
std::integral_constant<decltype(Vals), Vals>...>::template as<Tmp>;
};
What's the most efficient way to access the last template parameter?
You could use a little helper to convert the parameter pack into an array.
template<int... Args>
struct pack {
static constexpr std::array as_array{ Args... };
};
You can then get the last argument with array indexing:
template <int T1, int... Ts>
struct Test {
static constexpr int last = pack<Ts...>::as_array[sizeof...(Ts) - 1];
integer_sequence is a way:
template <typename SeqN, typename Seq> struct TestImpl;
template <int... Ns, std::size_t ... Is>
struct TestImpl<std::integer_sequence<int, Ns...>, std::index_sequence<Is...>>
{
private:
using SeqTuple = std::tuple<std::integral_constant<int, Ns>...>;
public:
static constexpr int sizes[] = {std::tuple_element_t<Is, SeqTuple>::value...};
Foo<std::tuple_element_t<Is, SeqTuple>::value...> foo;
};
template <int N1, int N2, int... Ns> // At least 2 numbers
using Test = TestImpl<std::integer_sequence<int, N1, N2, Ns...>,
std::make_index_sequence<1 + sizeof...(Ns)>>;
Demo
I have a function foo that calls a function bar with a subset of types passed into foo's variadic template. For example:
template <typename... T>
void foo() {
// ...
template <size_t start_idx, typename... T>
using param_pack = /*Parameter pack with T[start_idx]...T[N]*/
auto b = bar<param_pack<2, T...>>();
// ...
}
Is there a way to extract a "sub-parameter pack". In the above case
if T = [int float char double] then param_pack<2, T...> = [char double]
[EDIT]
My goal is to be able to use something like this to match event handlers. For example
struct ev {};
template <typename... T>
struct event : ev {
std::tuple<T...> data_;
event(T&&... d) : data_(std::make_tuple(std::forward<T>(d)...)) {}
};
template <typename... Functor>
struct handler {
std::tuple<Functor...> funcs_;
handler(Functor&&... f) : funcs_(std::make_tuple(std::forward<Functor>(f)...)) {}
void handle_message(ev* e) {
auto ptrs = std::make_tuple(
dynamic_cast<event<param_pack<1, typename function_traits<F>::args>>*>(e)...
);
match(ptrs);
}
};
Here function_traits::args get a parameter pack for the function arguments and match iterates over the the tuple funcs_ checking if the dynamic_cast was successful and executing the first successful function. I already have these implemented.
The handlers are something like
[] (handler* self, <ARGS>) -> void {
// ...
}
I am essentially trying to get rid of the self argument.
Set aside the fact that it lacks a check on the index N for simplicity, here is a possible solution based on a function declaration (no definition required) and an using declaration:
template<std::size_t N, typename... T, std::size_t... I>
std::tuple<std::tuple_element_t<N+I, std::tuple<T...>>...>
sub(std::index_sequence<I...>);
template<std::size_t N, typename... T>
using subpack = decltype(sub<N, T...>(std::make_index_sequence<sizeof...(T) - N>{}));
The good part of this approach is that you have not to introduce a new type designed around a tuple, then specialize it somehow iteratively.
It follows a minimal, working example that uses the code above:
#include<functional>
#include<tuple>
#include<cstddef>
#include<type_traits>
template<std::size_t N, typename... T, std::size_t... I>
std::tuple<std::tuple_element_t<N+I, std::tuple<T...>>...>
sub(std::index_sequence<I...>);
template<std::size_t N, typename... T>
using subpack = decltype(sub<N, T...>(std::make_index_sequence<sizeof...(T) - N>{}));
int main() {
static_assert(std::is_same<subpack<2, int, float, char, double>, std::tuple<char, double>>::value, "!");
}
See a full example up and running on wandbox.
The extended version that includes a check on the index N would look like this:
template<std::size_t N, typename... T, std::size_t... I>
std::enable_if_t<(N < sizeof...(T)), std::tuple<std::tuple_element_t<N+I, std::tuple<T...>>...>>
sub(std::index_sequence<I...>);
That is the type you can see in the first example once wrapped in a std::enable_if_t, nothing more. Again, declaration is enough, no definition required.
EDIT
If you want to use your own class template instead of an std::tuple, you can easily modify the code to do that:
#include<functional>
#include<tuple>
#include<cstddef>
#include<type_traits>
template<typename...>
struct bar {};
template<template<typename...> class C, std::size_t N, typename... T, std::size_t... I>
std::enable_if_t<(N < sizeof...(T)), C<std::tuple_element_t<N+I, std::tuple<T...>>...>>
sub(std::index_sequence<I...>);
template<template<typename...> class C, std::size_t N, typename... T>
using subpack = decltype(sub<C, N, T...>(std::make_index_sequence<sizeof...(T) - N>{}));
int main() {
static_assert(std::is_same<subpack<bar, 2, int, float, char, double>, bar<char, double>>::value, "!");
}
EDIT
According to the code added to the question, the solution above is still valid. You should just define your event class as it follows:
struct ev {};
template <typename>
struct event;
template <typename... T>
struct event<std::tuple<T...>>: ev {
// ...
};
This way, when you do this:
event<param_pack<1, typename function_traits<F>::args>>
You still get a tuple out of param_pack (that is the subpack using declaration in my example), but it matches the template partial specialization of event and the parameter pack is at your disposal as T....
This is the best you can do, for you cannot put a parameter pack in an using declaration. Anyway it just works, so probably it can solve your issue.
You may do something like:
template <std::size_t N, typename ... Ts> struct drop;
template <typename ... Ts>
struct drop<0, Ts...>
{
using type = std::tuple<Ts...>;
};
template <std::size_t N, typename T, typename ... Ts>
struct drop<N, T, Ts...>
{
using type = typename drop<N - 1, Ts...>;
};
// Specialization to avoid the ambiguity
template <typename T, typename... Ts>
struct drop<0, T, Ts...>
{
using type = std::tuple<T, Ts...>;
};
Here is a quick but not particularly reusable solution.
template <typename Pack, std::size_t N, std::size_t... Is>
void invoke_bar_impl(std::index_sequence<Is...>) {
bar<std::tuple_element_t<N + Is, Pack>...>();
}
template <std::size_t N, typename... Ts>
void invoke_bar() {
auto indices = std::make_index_sequence<sizeof...(Ts) - N>();
invoke_bar_impl<std::tuple<Ts...>, N>(indices);
}
Suppose I have a template which is parametrized by a class type and a number of argument types. a set of arguments matching these types are stored in a tuple. How can one pass these to a constructor of the class type?
In almost C++11 code:
template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return T(get<0>(args), get<1>(args), ...); }
};
How can the ... in the constructor call be filled without fixing the length?
I guess I could come up with some complicated mechanism of recursive template calls which does this, but I can't believe that I'm the first to want this, so I guess there will be ready-to-use solutions to this out there, perhaps even in the standard libraries.
C++17 has std::make_from_tuple for this:
template <typename T, typename... Args>
struct foo
{
std::tuple<Args...> args;
T gen() { return std::make_from_tuple<T>(args); }
};
You need some template meta-programming machinery to achieve that.
The easiest way to realize the argument dispatch is to exploit pack expansion on expressions which contain a packed compile-time sequence of integers. The template machinery is needed to build such a sequence (also see the remark at the end of this answer for more information on a proposal to standardize such a sequence).
Supposing to have a class (template) index_range that encapsulates a compile-time range of integers [M, N) and a class (template) index_list that encapsulates a compile-time list of integers, this is how you would use them:
template<typename T, typename... Args>
struct foo
{
tuple<Args...> args;
// Allows deducing an index list argument pack
template<size_t... Is>
T gen(index_list<Is...> const&)
{
return T(get<Is>(args)...); // This is the core of the mechanism
}
T gen()
{
return gen(
index_range<0, sizeof...(Args)>() // Builds an index list
);
}
};
And here is a possible implementation of index_range and index_list:
//===============================================================================
// META-FUNCTIONS FOR CREATING INDEX LISTS
// The structure that encapsulates index lists
template <size_t... Is>
struct index_list
{
};
// Collects internal details for generating index ranges [MIN, MAX)
namespace detail
{
// Declare primary template for index range builder
template <size_t MIN, size_t N, size_t... Is>
struct range_builder;
// Base step
template <size_t MIN, size_t... Is>
struct range_builder<MIN, MIN, Is...>
{
typedef index_list<Is...> type;
};
// Induction step
template <size_t MIN, size_t N, size_t... Is>
struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
{
};
}
// Meta-function that returns a [MIN, MAX) index range
template<unsigned MIN, unsigned MAX>
using index_range = typename detail::range_builder<MIN, MAX>::type;
Also notice, that an interesting proposal by Jonathan Wakely exists to standardize an int_seq class template, which is something very similar to what I called index_list here.
Use index_sequence to unpack a std::tuple (or std::pair, std::array, or anything else supporting the tuple interface):
#include <utility>
#include <tuple>
template <typename Tuple, std::size_t... Inds>
SomeClass help_make_SomeClass(Tuple&& tuple, std::index_sequence<Inds...>)
{
return SomeClass(std::get<Inds>(std::forward<Tuple>(tuple))...);
}
template <typename Tuple>
SomeClass make_SomeClass(Tuple&& tuple)
{
return help_make_SomeClass(std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<Tuple>::value>());
}
std::index_sequence and std::make_index_sequence will be in C++1y. If you can't find a header that defines them, you could use these:
template <std::size_t... Inds>
struct index_sequence {
static constexpr std::size_t size()
{ return sizeof...(Inds); }
};
template <std::size_t N, std::size_t... Inds>
struct help_index_seq {
typedef typename help_index_seq<N-1, N-1, Inds...>::type type;
};
template <std::size_t... Inds>
struct help_index_seq<0, Inds...> {
typedef index_sequence<Inds...> type;
};
template <std::size_t N>
using make_index_sequence = typename help_index_seq<N>::type;
Live example, in C++11 mode: http://coliru.stacked-crooked.com/a/ed91a67c8363061b
C++14 will add standard support for index_sequence:
template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return gen_impl(std::index_sequence_for<Args...>()); }
private:
template <size_t... Indices>
T gen_impl(std::index_sequence<Indices...>) { return T(std::get<Indices>(args)...); }
};
You'll need to use the indices trick, which means a layer of indirection:
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return gen(build_indices<sizeof...(Args)>{}); }
private:
template<std::size_t... Is>
T gen(indices<Is...>) { return T(get<Is>(args)...); }
};
Create a sequence of indexes from 0 through n-1:
template<size_t... indexes>
struct seq {};
template<size_t n, size_t... indexes>
struct make_seq: make_seq<n-1, n-1, indexes...> {};
template<size_t... indexes>
struct make_seq: make_seq<0, indexes...> {
typedef seq<indexes...> type;
};
unpack them in parallel with your args, or as the index to get<> in your case.
The goal is something like:
template< typename T, typename Tuple, typename Indexes >
struct repack;
template< typename... Ts, size_t... indexes >
struct repack< tuple<Ts...>, seq<indexes...> > {
T operator()( tuple<Ts...> const& args ) const {
return T( get<indexes>(args)... );
}
};
use repack in your gen like this:
T gen() {
repack<T, tuple<Args...>, typename make_seq<sizeof...(Args)>::type> repacker;
return repacker( args );
}
Suppose I have a template which is parametrized by a class type and a number of argument types. a set of arguments matching these types are stored in a tuple. How can one pass these to a constructor of the class type?
In almost C++11 code:
template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return T(get<0>(args), get<1>(args), ...); }
};
How can the ... in the constructor call be filled without fixing the length?
I guess I could come up with some complicated mechanism of recursive template calls which does this, but I can't believe that I'm the first to want this, so I guess there will be ready-to-use solutions to this out there, perhaps even in the standard libraries.
C++17 has std::make_from_tuple for this:
template <typename T, typename... Args>
struct foo
{
std::tuple<Args...> args;
T gen() { return std::make_from_tuple<T>(args); }
};
You need some template meta-programming machinery to achieve that.
The easiest way to realize the argument dispatch is to exploit pack expansion on expressions which contain a packed compile-time sequence of integers. The template machinery is needed to build such a sequence (also see the remark at the end of this answer for more information on a proposal to standardize such a sequence).
Supposing to have a class (template) index_range that encapsulates a compile-time range of integers [M, N) and a class (template) index_list that encapsulates a compile-time list of integers, this is how you would use them:
template<typename T, typename... Args>
struct foo
{
tuple<Args...> args;
// Allows deducing an index list argument pack
template<size_t... Is>
T gen(index_list<Is...> const&)
{
return T(get<Is>(args)...); // This is the core of the mechanism
}
T gen()
{
return gen(
index_range<0, sizeof...(Args)>() // Builds an index list
);
}
};
And here is a possible implementation of index_range and index_list:
//===============================================================================
// META-FUNCTIONS FOR CREATING INDEX LISTS
// The structure that encapsulates index lists
template <size_t... Is>
struct index_list
{
};
// Collects internal details for generating index ranges [MIN, MAX)
namespace detail
{
// Declare primary template for index range builder
template <size_t MIN, size_t N, size_t... Is>
struct range_builder;
// Base step
template <size_t MIN, size_t... Is>
struct range_builder<MIN, MIN, Is...>
{
typedef index_list<Is...> type;
};
// Induction step
template <size_t MIN, size_t N, size_t... Is>
struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
{
};
}
// Meta-function that returns a [MIN, MAX) index range
template<unsigned MIN, unsigned MAX>
using index_range = typename detail::range_builder<MIN, MAX>::type;
Also notice, that an interesting proposal by Jonathan Wakely exists to standardize an int_seq class template, which is something very similar to what I called index_list here.
Use index_sequence to unpack a std::tuple (or std::pair, std::array, or anything else supporting the tuple interface):
#include <utility>
#include <tuple>
template <typename Tuple, std::size_t... Inds>
SomeClass help_make_SomeClass(Tuple&& tuple, std::index_sequence<Inds...>)
{
return SomeClass(std::get<Inds>(std::forward<Tuple>(tuple))...);
}
template <typename Tuple>
SomeClass make_SomeClass(Tuple&& tuple)
{
return help_make_SomeClass(std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<Tuple>::value>());
}
std::index_sequence and std::make_index_sequence will be in C++1y. If you can't find a header that defines them, you could use these:
template <std::size_t... Inds>
struct index_sequence {
static constexpr std::size_t size()
{ return sizeof...(Inds); }
};
template <std::size_t N, std::size_t... Inds>
struct help_index_seq {
typedef typename help_index_seq<N-1, N-1, Inds...>::type type;
};
template <std::size_t... Inds>
struct help_index_seq<0, Inds...> {
typedef index_sequence<Inds...> type;
};
template <std::size_t N>
using make_index_sequence = typename help_index_seq<N>::type;
Live example, in C++11 mode: http://coliru.stacked-crooked.com/a/ed91a67c8363061b
C++14 will add standard support for index_sequence:
template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return gen_impl(std::index_sequence_for<Args...>()); }
private:
template <size_t... Indices>
T gen_impl(std::index_sequence<Indices...>) { return T(std::get<Indices>(args)...); }
};
You'll need to use the indices trick, which means a layer of indirection:
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return gen(build_indices<sizeof...(Args)>{}); }
private:
template<std::size_t... Is>
T gen(indices<Is...>) { return T(get<Is>(args)...); }
};
Create a sequence of indexes from 0 through n-1:
template<size_t... indexes>
struct seq {};
template<size_t n, size_t... indexes>
struct make_seq: make_seq<n-1, n-1, indexes...> {};
template<size_t... indexes>
struct make_seq: make_seq<0, indexes...> {
typedef seq<indexes...> type;
};
unpack them in parallel with your args, or as the index to get<> in your case.
The goal is something like:
template< typename T, typename Tuple, typename Indexes >
struct repack;
template< typename... Ts, size_t... indexes >
struct repack< tuple<Ts...>, seq<indexes...> > {
T operator()( tuple<Ts...> const& args ) const {
return T( get<indexes>(args)... );
}
};
use repack in your gen like this:
T gen() {
repack<T, tuple<Args...>, typename make_seq<sizeof...(Args)>::type> repacker;
return repacker( args );
}