Distribute template wrapper across parameter pack - c++

I have a couple of templated types, Egg<T> and Chick<T>.
template<typename T>
struct Egg{};
template<typename T>
struct Chick{};
The chicks are contained in a class LoudNest<Chicks...> and the eggs in QuietNest<Eggs...>:
template <typename... Chicks>
struct LoudNest {
std::tuple<Chicks...> chicks;
};
template <typename... Eggs>
struct QuietNest {
std::tuple<Eggs...> eggs;
// more here.
};
I want to have a hatch method on QuietNest<Eggs...> that produces a LoudNest. The LoudNest should have a Chick<T> for each Egg<T> in the QuietNest. I have a function QuietNest<Eggs...>::hatch_impl that can create a std::tuple<Chicks...> where the Chicks all have the correct type parameters. That is, QuietNest<Egg<double>, Egg<string>, Egg<char>>::hatch_impl will return std::tuple<Chick<double>, Chick<string>, Chick<char>>. I'm getting stuck trying to wrap that in a LoudNest constructor:
template <typename... Eggs>
struct QuietNest {
std::tuple<Eggs...> eggs;
auto hatch() const {
// hatchlings is a std::tuple of chicks templated how I want.
auto hatchlings = std::apply(
[&](auto... args) { return hatch_impl(std::make_tuple(), args...); },
eggs);
// This line causes an error:
return LoudNest{hatchlings};
// error: cannot refer to class template 'LoudNest' without a template argument
}
// The rest of this all works, but is included in case you want to poke at it:
// base case: only one parameter was passed—the tuple of hatched chicks.
template<typename...Chicks>
std::tuple<Chicks...> hatch_impl(std::tuple<Chicks...> chicks) {
return chicks;
}
// recursive case: in addition to the tuple of hatched chicks,
// at least one egg was passed (possibly more in the tail)
template<typename...Chicks, typename T, typename...Unhatched>
std::tuple<Chicks..., Chick<T>> hatch_impl(
std::tuple<Chicks...> chicks,
const Egg<T>& egg,
Unhatched... tail
) const {
Chick<T> babyBird = hatchOne(egg);
return hatch_impl(
std::tuple_cat(chicks, std::make_tuple(babyBird)),
tail...);
}
template<T>
Chick<T> hatchOne(Egg<T> egg) { return Chick<T>{}; }
};
I'm thinking I need to make a "converter" that accepts a parameter pack of eggs and produces a LoudNest with chicks of the corresponding types. Starting with converting a single Egg<T> to a Chick<T>, I have:
template<typename T>
struct AsChick {
using type = T;
};
template< template <typename> class E, typename T>
struct AsChick<E<T>> {
static_assert(std::is_same<E<T>, Egg<T>>::value, "Expected AsChick to be used with an Egg<T>");
using type = Chick<T>;
};
Where I'm getting stuck is when I try to do the same for a parameter pack:
template<typename... Eggs>
struct AsLoudNest1 {
using type = LoudNest<
(AsChick<Eggs>::type)...
// I want this to expand Eggs to produce
// AsChick<Eggs0>::type, AsChick<Eggs1>::type, AsChick<Eggs2>::type, ...
// but it doesn't looks like that's a supported type of expansion
>;
};
static_assert(std::is_same<
AsLoudNest1<Egg<int>, Egg<double>>::type,
LoudNest<Chick<int>, Chick<double>>
>::value, "Expected AsLoudNest1 to convert my Egg<T>s to Chick<T>s");
And try number two:
template <
class E, // does this need to be template<typename> class E?
typename... Rest>
struct AsLoudNest2 {
using type = LoudNest<
// Pretty sure the beginning is right.
AsChick<E>::type,
// This line feels wrong, AsLoudNest2<...>::type is a concrete type, not a parameter pack
AsLoudNest2<Rest...>::type...
>;
};
// also, feels like I need a base case for AsLoudNest2?
My actual problem has to do with implementing an interpreter, and the classes are FormalParameter<T> (Egg<T>), ActualParameter<T> (Chick<T>), etc. However, I wanted to avoid using the word "parameter" for in the example code, as we're already talking about Parameter Packs in a different sense.
code from this post: https://godbolt.org/z/XBIEhm

I was able to fix your example with a few changes: https://godbolt.org/z/3VW68f
Add a deduction guide to LoudNest to alleviate the problem deducing the Chicks... types in LoudNest{hatchlings} (this probably isn't the only solution, but seemed clean in that it didn't require complicating the hatch() implementation):
template<typename... Chicks>
LoudNest(const std::tuple<Chicks...>& chicks) -> LoudNest<Chicks...>;
(Add hatchOne which was present in your question but not the godbolt link you shared)
Get rid of hatch_impl in favor of just calling hatchOne during pack expansion:
auto hatchlings = std::apply(
[&](auto... args) { return std::make_tuple(hatchOne(args)...); },
eggs);
Use a specialization to deduce the inner T types of the Egg parameters to AsLoudNest1:
template<typename... Eggs>
struct AsLoudNest1 {};
template<typename... Ts>
struct AsLoudNest1<Egg<Ts>...> {
using type = LoudNest<Chick<Ts>...>;
};

Related

Implementation of typed tuple wrapper

How can an implementation look like, that wraps around e.g. a std::tuple as a static list of type/value, plus a type (not contained in tuple) to refer to some kind of owner/visitor.
I want to instantiate like
constexpr auto data = data_of<a>(1, 2.0);
Background
The idea is to use a data_of<T>(...) kind of structure to to pass a list of type/data pairs into a bulk function like this.
template <typename... _Ts>
static constexpr void do_bulk_stuff(_Ts&&... _Vs)
{
// crazy stuff happens here
}
// call it like
do_bulk_stuff
(
data_of<a>(1, 2.0),
data_of<b>(3),
data_of<c>(4.0, 5, 6),
// ...
);
Attempt 1
So far I ended up with a naive (not working) implementation attempt like
template <typename T, typename... Ts>
struct data_of {
using type = T;
using data_t = std::tuple<Ts...>;
data_t data;
constexpr data_of(Ts&&... Vs)
: data(Vs...)
{}
};
Goal
My goal is to achieve a result like this data_of<a> instance pseudo code example
{
// meta
type = a;
data_t = std::tuple<int,double>;
// runtime
data = [1, 2.0];
}
The issue inherent to your attempt is that class template argument deduction is simply not like its function counterpart. There will be no deduction if any of the class template's arguments is explicitly specified. You fail because the trailing pack is always specified (by omission) as empty.
The solution is to shift the burden onto the mechanism that allows you to specify only part of the arguments: function templates.
template <typename T, typename... Ts>
struct data_of_t {
using type = T;
using data_t = std::tuple<Ts...>;
data_t data;
constexpr data_of_t(Ts&&... vs)
: data(std::forward<Ts>(vs)...)
{}
};
template<typename T, typename... Ts>
constexpr auto data_of(Ts&&... vs) {
return data_of_t<T, Ts...>(std::forward<Ts>(vs)...);
}
Now the type of the expression data_of<a>(1, 2.0) has the same "meta" properties you are after.

Generate function with signature of pointer's type passed to template

I want to create a generator which for each pointer to function will create a static function to which the pointer can point to:
template <auto &PtrToIsrHandler, auto MemberFunction> struct enable_member_isr_handler
{
using TypeOfCFunPtr = std::remove_reference_t<decltype(PtrToIsrHandler)>;
using TypeOfCFunPointed = std::remove_pointer_t<TypeOfCFunPtr>;
using RetType = std::invoke_result_t<TypeOfCFunPointed>;
static RetType isr_handler(/* dunno what to put here */)
{
return /* call MemberFunction here somehow */;
}
enable_member_isr_handler()
{
PtrToIsrHandler = isr_handler;
}
};
In the parameter list of the isr_handler method I tried to put a tuple by using:
template <typename T> struct get_parameters;
template <typename Ret, typename... Args> struct get_parameters<Ret(Args...)>
{
using args_t = std::tuple<Args...>;
};
But I get then:
error: invalid conversion from void (*)(get_parameters<void()>)}’ to ‘void (*)()’
How can I make it in such a way that PtrToIsrHandler could be a valid pointer to isr_handler?
As mentioned in my comment, one approach to get the argument list is to use partial specialization and forward the type of the passed in member function. The same approach can be used on free functions as well.
#include <iostream>
template <auto MemberFunction, class MemberFunctionType>
struct handler_impl;
template <auto MemberFunction, class ReturnType, class ClassType, class... Args>
struct handler_impl<MemberFunction, ReturnType(ClassType::*)(Args...)> {
// here you have access to return-type, class-type and args
static ReturnType call_on_instance(ClassType& obj, Args... args) {
return (obj.*MemberFunction)(args...);
}
};
template <auto MemberFunction>
using handler = handler_impl<MemberFunction, decltype(MemberFunction)>;
struct Foo {
int print(int x) {
std::cout << x*x << std::endl;
return x;
}
};
int main() {
Foo f;
handler<&Foo::print>::call_on_instance(f, 7);
}
One thing to keep in mind here is that we are not using perfect forwarding. The easiest approach is to simply make call_on_instance a template function, then we don't really need to care about the arguments and return value, we can let the compiler deduce it.
Another option is to use the approach I showed above and use a static_assert to make sure the argument list passed in is valid, and thus give a better error message when used in the wrong way.

Extracting a tuple of value_type from a tuple of containers in C++11

I have a function with a template parameter which I know to be a std::tuple of several standard C++ containers of varying element types.
How can I extract, out of this, a type that is a std::tuple of the element types?
For example, suppose I have the following function
template <typename TupOfCtrs>
void doStuff(const TupOfCtrs& tupOfCtrs) {
using TupOfElements = /*extract a tuple type by applying CtrT::value_type to each container in tupOfCtrs and combining the results into an std::tuple*/;
MyHelperClass<TupOfElements> helper;
}
and I know it is being called like this:
std::list<Foo> l {/*...*/};
std::vector<Bar> v {/*...*/};
std::deque<Baz> d {/*...*/};
auto tup = std::make_tuple(l, v, d);
In this case, I want the TupOfElements helper type to be defined as std::tuple<Foo, Bar, Baz>.
Note that I do not need to actually create the tuple, only to get its type.
How can this be achieved, possibly using the Boost::Fusion library?
You can do this even in a more simple manner without Boost Fusion like this:
// Template which takes one type argument:
template <typename Tuple> struct TupOfValueTypes;
// Only provide a definition for this template for std::tuple arguments:
// (i.e. the domain of this template metafunction is any std::tuple)
template <typename ... Ts>
struct TupOfValueTypes<std::tuple<Ts...> > {
// This definition is only valid, if all types in the tuple have a
// value_type type member, i.e. the metafunction returns a type only
// if all types of the members in the std::tuple have a value_type
// type member, and a std::tuple can be constructed from these:
using type = std::tuple<typename Ts::value_type...>;
};
template <typename TupOfCtrs>
void doStuff(const TupOfCtrs& tupOfCtrs) {
using TupOfElements = typename TupOfValueTypes<TupOfCtrs>::type;
// ...
}
But it is of course easier to specify doStuff for the std::tuple explicitly:
template <typename ... Ts>
void doStuff(const std::tuple<Ts...> & tupOfCtrs) {
using TupOfElements = std::tuple<typename Ts::value_type...>;
// ...
}
PS: Also note, that in many cases if you need to just have a list of types, the std::tuple class is an overkill, and might slightly hurt compilation times. Personally, I've always instead used a simple TypeList struct:
template <typename ... Ts> struct TypeList
{ using type = TypeList<Ts...>; };
If you want doStuff to take a std::tuple, make that explicit:
template <class... Ts>
void doStuff(std::tuple<Ts...> const& tupOfCtr) { ... }
Once you have that parameter pack, it's just a matter of pulling out the value_type:
template <class... Ts>
void doStuff(std::tuple<Ts...> const& tupOfCtr)
{
using value_tuple = std::tuple<typename Ts::value_type...>;
// ...
}

What is the most compact way to extract the template arguments of a class and iterate over them?

In the little program below, I show the solution I currently use to extract the template arguments of a class and iterate over it via a recursive helper function.
I wonder if there is a more concise way to do it, as I explain in the pseudo-code in the comments below.
template <int...Is> struct Pack {};
template <int I> struct B
{
static void foo() { std::cout << I << "\n"; }
};
// recursive helper function, also used to extract the parameter pack arguments
template <int I, int...Is>
void foo_helper( Pack<I, Is...>&& )
{
B<I>::foo();
foo_helper( Pack<Is...>{} );
}
// terminate recursion
void foo_helper( Pack<>&& ) {}
struct A
{
typedef Pack<1,3,5> ints;
static void foo()
{
// this is what I do
foo_helper(ints{});
// this is what I would like to do, ideally in one single line
// 1) extract the template arguments pack from ints, without creating an helper function for that
// 2) iterate on the template arguments of the pack without a recursive helper
// In pseudocode, something like:
// (B<IterateOver<ArgumentsOf<ints>>>::foo());
}
};
int main()
{
A::foo();
}
If you want to do metaprogramming, start working in types. If you want non-type template parameters, move them over to types asap.
Below, I first take Pack<1,2,3> and convert it to types< std::integral_constant<int, 1>, std::integral_constant<int, 2>, std::integral_constant<int, 3> >. This is a list of types that is in obvious correspondence to your pack of ints.
Then, I introduce a tag type template. This is a type which "carries" another type, but it itself is stateless. You can extract the type from an value of an instance of the template as a bonus.
Third, I write a "for each type" function that takes a lambda and a pack of types, and proceeds to call the lambda once for each of the types, passing in a tag type.
In the body of the lambda, we can extract the passed type by using decltype on the tag variable (or a helper macro).
We chain those together, and from the passed tag type we can extract the integer in the original pack.
The result is you can inject this into your code:
for_each_type( [&](auto tag){
constexpr int i = TAG_TYPE(tag){};
// use i
}, ints_as_types_t<ints>{} );
in the middle of your method, and work on the ints "inline".
If we wanted to only solve your specific problem, we'd do a bit less boilerplate, but I like the genericness.
template<class...>struct types{using type=types;};
template <int...Is> struct Pack {};
template<class pack> struct ints_as_types;
template<class pack>
using ints_as_types_t=typename ints_as_types<pack>::type;
template<class T, template<T...>class pack, T...ts>
struct ints_as_types<pack<ts...>> {
using type=types<std::integral_constant<T,ts>...>;
};
now we can do:
using pack = ints_as_types_t<Pack<1,2,3>>;
and pack is a list of types, not a list of integers.
Now some hana-style metaprogramming: (metaprogramming with values instead of pure types)
template<class T>struct tag_t{using type=T; constexpr tag_t(){};};
template<class T>constexpr tag_t<T> tag={};
template<class Tag>using type_t=typename Tag::type;
#define TAG_TYPE(...) type_t<std::decay_t<decltype(__VA_ARGS__)>>;
template<class F, class...Ts>
void for_each_type(F&& f, types<Ts...>) {
using discard=int[];
(void)discard{ 0, ((
f(tag<Ts>)
),void(),0)...};
}
which lets you iterate over a collection of types.
for_each_type( [&](auto tag){
constexpr int i = TAG_TYPE(tag){};
// use i
}, ints_as_types_t<ints>{} );
gives you a lambda that has a constexpr int i for each of the types in your list.
A bunch of the above work lifts your list of ints into a list of types, because working with only types makes metaprogramming less special-case. You can skip that lifting, and write a for_each_integer that takes a Pack<int...> directly with less code, but it seems less useful to me.
You could add a foo_for_each function to Pack:
template <int...Is> struct Pack {
template <template <int> class T>
static void foo_for_each () {
std::initializer_list<int> { (T<Is>::foo(),0)... } ;
}
};
Then you would just write:
ints::foo_for_each<B>();
This will call B<N>::foo for each N in the pack.
As suggested by Yakk, you could pass in a lambda which gets a tag type as an argument to create a generic Pack::for_each:
template <typename T> struct tag { using type = T; };
template <typename T> using type_t = typename T::type;
template <int...Is> struct Pack {
template <template <int> class T, typename Func>
static void for_each (Func&& func) {
std::initializer_list<int> {
((std::forward<Func>(func)(tag<T<Is>>{})) 0)...
} ;
}
};
Then you could call like this:
auto call_foo = [](auto tag) { type_t<decltype(tag)>::foo(); };
ints::for_each<B>(call_foo);
This is the shortest I can come up with:
#include <iostream>
template<int... Is>
struct Pack;
template <int I> struct B
{
static void foo() { std::cout << I << "\n"; }
};
template<typename PACK> struct unpack;
template<int...Is>
struct unpack<Pack<Is...>>
{
template<template<int> class T>
static void call()
{
using swallow = int[sizeof...(Is)];
(void) swallow{(T<Is>::foo(), 0)...};
}
};
struct A
{
typedef Pack<1,3,5> ints;
static void foo()
{
unpack<ints>::call<B>();
}
};
int main()
{
A::foo();
}
If you want to have the variadic pack for runtime-iteration you could attach a std::arrayto your struct Pack as:
template <int...Is> struct Pack {
std::array<int, sizeof...(Is)> arr = {{Is...}};
};
And then iterate through as:
static void foo() {
for(auto && i : ints{}.arr) std::cout << i << " ";
}
Live Demo
What you wrote here is just plain weird, where did you even find an implementation this
rigid ?
You NEED a helper function, it's just a fact, you could probably work around it
somehow, but I do not see the point of that.
The only solution for that, right now, is to use Clang 3.6, they already implemented
the new syntax, that allows you to write something like this.
// I am pretty sure, this was the syntax, it's called a fold expression
// you can read more about it here:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4295.html
template<typename ... Type>
auto sum(Type ... argument)
{
return (... + argument);
}
In any other compiler, the way to go about it, is to write two simple functions
template<typename Tail>
auto sum(Tail tail)
{
return tail;
}
template<typename Head, typename ... Tail>
auto sum(Head head, Tail ... tail)
{
return head + sum(tail);
}
This accepts anything that supports + so strings, ints, doubles will work, probably
some more, but you get the gist of it.
Your example would look like this
template<typename Tail>
void print(Tail tail)
{
cout << tail << endl;
}
template<typename Head, typename ... Tail>
void print(Head head, Tail ... tail)
{
cout << head;
print(tail...);
}
Usage:
print(1, 3.14, "something", string{"yeye"}, 52);
or
sum(1, 512, 55, 91);
There are some other ways to use variadic templates, like this guy here describes,
there is way too much of it, for me to put it here, so I'll just link:
http://florianjw.de/en/variadic_templates.html
Iterating over the arguments of a template is a bit harder, because you have to use
some real compiler magic and index_sequence.
I have an example lying around here somewhere, because I have been messing around
with it lately.
template<typename InputTuple, std::size_t ... N>
void tupleIteratorImpl(InputTuple& input, std::index_sequence<N...>)
{
// DO WHATEVER YOU WANT HERE, but the structure is
FUNCTION(/* pass all of the template parameters as arguments */, std::get<N>(input)...);
// and FUNCTION has to have the structure of the examples from point 1.
// but with this, you can already do pretty much anything you imagine
// even at compile time
}
template<typename InputTuple, typename Indices = std::make_index_sequence<std::tuple_size<InputTuple>::value>>
void tupleIterator(InputTuple& input)
{
tupleIteratorImpl(input, Indices());
}
A function for this is already included in c++17, and it is called apply, here's the documentation:
http://en.cppreference.com/w/cpp/experimental/apply with some sample code even.
Hope this answers some of your questions.

How to initialize all tuple elements by the same arguments?

Is it possible to initialize all elements of std::tuple by the same argument, using the non-default constructors of the underlying types?
template <typename... TElements>
struct Container {
// I'd wish to be able to do something like this:
Container(Foo foo, Bar bar)
: tuple(foo, bar)
{}
std::tuple<TElements...> tuple;
};
The point is that I don't know the tuple size (it's templated by a variadic parameter), so I can't duplicate the arguments as many times as I need. The only thing I know is that all types in TElements have a constructor taking Foo and Bar as arguments and don't have a default constructor.
The clearest way is just to construct each element in the tuple constructor argument list:
template <typename... TElements>
struct Container {
Container(Foo foo, Bar bar)
: tuple(TElements{foo, bar}...)
{}
std::tuple<TElements...> tuple;
};
This will result in move (or copy) constructing each element of the tuple from its corresponding constructor parameter; if this is unacceptable you could use piecewise construction:
template <typename... TElements>
struct Container {
Container(Foo foo, Bar bar)
: tuple(std::piecewise_construct, (sizeof(TElements), std::tie(foo, bar))...)
{}
std::tuple<TElements...> tuple;
};
Unfortunately in this case we have to do some kind of gymnastics (here sizeof and a comma operator) to get the variadic list TElements mentioned and ignored.
with double parameter pack expansion you can (try to) construct each element of a given tuple class with all given parameters to a function:
template <class T> struct tuple_construct_t;
template <class... Ts> struct tuple_construct_t<std::tuple<Ts...>> {
template <class... Args>
static std::tuple<Ts...> make_tuple(Args&&... args) {
//this is the central part - the double pack expansion
return std::make_tuple(Ts{args...}...);
}
};
// a little free helper function...
template <class Tup, class... Args>
Tup construct_tuple(Args&&... args) {
return tuple_construct_t<Tup>::make_tuple(std::forward<Args>(args)...);
}
And then somewhere in the code:
typedef std::tuple<NoDefault1, NoDefault2> myTuple;
auto t = construct_tuple<myTuple>(Foo{}, Bar{});
full working example: Link
Edit:
Since #Rakvan deleted his answer, I'll preserve the second (correct) part of it:
template <class ... Ts, class ... Args>
std::tuple<Ts...> cartesian_make_tuple(Args && ... args)
{
return std::make_tuple(Ts{args...}...);
}
here is a working exaple
We want to do variadic expansion (to get just the right amount of parameters), but we have to put a ‘hint’ to tie the expansion to whichever pack it is we want to match:
template<typename Dummy, typename Value>
Value depends(Value&& value)
{ return std::forward<Value>(value); }
template<typename... Elements>
void example()
{
// naive attempt to construct all the elements from 0:
// std::tuple<Elements...> t { 0... };
// now expansion is tied to the Elements pack
std::tuple<Elements...> t { depends<Elements>(0)... };
// with two arguments:
std::tuple<Elements...> t { { depends<Elements>(0), depends<Elements>(1) }... };
}