How to initialize all tuple elements by the same arguments? - c++

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) }... };
}

Related

Distribute template wrapper across parameter pack

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>...>;
};

Unpack parameter pack into std::initializer_list?

Is there any way to use a parameter pack to create an initializer list of objects or to insert objects into a std::vector? The problem I am having is all examples of parameter packs I have seen use passed arguments for the compiler to be able to differentiate which function it needs to call. The thing is that I have no arguments to pass to the functions just the types.
Example:
// compiler cannot determine which function is correct
namespace impl
{
template<class T, class... U>
void get_type_impl(std::vector<MetaClass*>& types)
{
// rusty::get<T>(); just retrieves a MetaClass object for the specified type
types.emplace_back(rusty::get_type<T>());
impl::get_type_impl<U...>(types);
}
template <class T>
void get_type_impl(std::vector<MetaClass*>& types)
{
types.emplace_back(rusty::get_type<T>());
}
}
template <class... T>
std::vector<MetaClass*> get_types()
{
std::vector<MetaClass*> types;
types.reserve(sizeof...(T));
impl::get_type_impl<T...>(types);
return types;
}
Example Usage:
auto types = get_types<MovementComponent, GraphicsComponent>();
Edit:
The goal is to create a vector of objects that are created from the provided template types. The current problem I have is that the compiler cannot deduce which function to use. As both get_type_impl can have the same function signature.
Solution:
namespace impl
{
template <class T>
void get_type_impl(std::vector<MetaClass*>& types)
{
types.emplace_back(rusty::get_type<T>());
}
template<class T0, class T1, class... Tn>
void get_type_impl(std::vector<MetaClass*>& types)
{
types.emplace_back(rusty::get_type<T0>());
impl::get_type_impl<T1, Tn...>(types);
}
}
template <class... T>
std::vector<MetaClass*> get_types()
{
std::vector<MetaClass*> types;
types.reserve(sizeof...(T));
impl::get_type_impl<T...>(types);
return types;
}
The solution is to force one of the get_type_impl to take at least 2 template types and the other to simply take 1. This creates enough a difference in the signatures for the compiler to determine which is the correct function.
Not sure to understand but... it seems to me that you'r looking for something as follows (caution: code not tested):
template <typename ... Ts>
std::vector<MetaClass*> get_types()
{ return { rusty::get_type<Ts>()... }; }
Otherwise, to solve the problem with get_types_impl(), I suggest to delete the second function
template <class T>
void get_type_impl(std::vector<MetaClass*>& types)
{
types.emplace_back(rusty::get_type<T>());
}
and substitute it with the following ground case
template <int = 0>
void get_type_impl (std::vector<MetaClass*> const &)
{ }
The idea behind this is add (emplace_back()) elements in types through the first version of get_types_impl() and make so the last call, when the variadic type list U... is empty and is called
impl::get_type_impl<>(types);
, is hijacked (thanks the default not type template parameter int=0) to the ground case.

Create object from class name using a string in C++

I have a Base class:
class Base() {
public:
Base(int, int);
~Base();
};
I have multiple classes that inherit from Base:
class childA : public Base {
public:
childA(int, int, string);
~childA();
};
childA::childA(int x, int y, string str) : Base (x, y)
{
// do something here
}
Same for childB, childC, etc
I want to know if it's possible to create childA, childB or childC using a string. I heard about variadic tempaltes but I don't really understand how to use it.
Variadic template is a template, which can take an arbitrary number of template arguments of any type. Both the functions could be variadic since dawn of C language (printf function, for example), then macros and now - templates.
You can declare it like this:
template<typename... Arguments> class Variadic;
then specialize it with any number of arguments, including zero:
Variadic<double> instance;
Variadic<double, std::string> instance;
Variadic<> instance;
Then you may use the argument list, known as argument pack, like this:
template<typename... Arguments> void SampleFunction(Arguments... parameters);
Just as in case of variadic functions, the argument pack can be preceded by concrete arguments:
template<typename First, typename... Rest> class BunchOfValues;
There is classic example of variadic template in STL: std::tuple. Some compilers do not support this feature fully or do not support at all, and in their case tuple is implemented through metaprogramming and macro definitions.
There is no direct way in C++ to select particular argument from the list, like it is possible with variadic functions. It's possible to use recursion to iterate through them in one direction:
template<typename T> foo(T first)
{
// do something;
}
template<typename T, typename U, typename ... Args> foo(T first, U second, Args... Rest)
{
// do something with T
foo(second, Rest...);
}
Usually iteration would rely on function overloading, or - if the function can simply pick one argument at a time - using a dumb expansion marker:
template<typename... Args> inline void pass(Args&&...) {}
which can be used as follows:
template<typename... Args> inline void expand(Args&&... args) {
pass( some_function(args)... );
}
expand(42, "answer", true);
which will expand to something like:
pass( some_function(arg1), some_function(arg2), some_function(arg3) etc... );
The use of this "pass" function is necessary, since the expansion of the argument pack proceeds by separating the function call arguments by commas, which are not equivalent to the comma operator. some_function(args)...; will never work. Moreover, this above solution will only work when the return type of some_function is not void. Furthermore, the some_function calls will be executed in an unspecified order, because the order of evaluation of function arguments is undefined. To avoid the unspecified order, brace-enclosed initializer lists can be used, which guarantee strict left-to-right order of evaluation. To avoid the need for a not void return type, the comma operator can be used to always yield 1 in each expansion element.
struct pass {
template<typename ...T> pass(T...) {}
};
pass{(some_function(args), 1)...};
The number of arguments in argument pack can be determined by sizeof...(args) expression.
As of creating initializers that use calls name it is possible only if name is defined at time of writing the code. There stingizer operator # in preprocessor that can be used, e.g.
#define printstring( x ) printf(#x "\n")
printstring( This a dumb idea );
will generate code (assuming that C++ automatically joins string literals):
printf("This a dumb idea \n")
You can declare something like this:
template<typename T> class moniker
{
public:
moniker(const char* tname);
}
#define declare_moniker(type, name) moniker<type> name(#type)
How would variadic macro definitions and variadic template interact? I'm not sure. Compiler I have at hand failed, but it isn't C++11. Try that, if interested.
There might be typeid operator supporeted, depending on compiler settings.
const std::type_info& ti1 = typeid(A);
std::type_info got method name(), but string it returns is implementation dependant: http://en.cppreference.com/w/cpp/types/type_info/name
In c++14 you could create some helper struct to determine each character of the string you pass at compile-time and to forward it to a type. However string you pass need to be stored in variable with linkage to let compiler to use it as a non-type template parameter:
#include <utility>
#include <type_traits>
template <char... Cs>
struct string_literal { };
template <class T, T &, class>
struct make_string_literal_impl;
template <class T, T &Cs, std::size_t... Is>
struct make_string_literal_impl<T, Cs, std::index_sequence<Is...>> {
using type = string_literal<Cs[Is]...>;
};
template <class T, T &>
struct make_string_literal;
template <class T, std::size_t N, T (&Cs)[N]>
struct make_string_literal<T[N], Cs>: make_string_literal_impl<T[N], Cs, std::make_index_sequence<N>> {
};
struct Base {
Base(int, int) { }
~Base() { }
};
template <class>
struct Child: Base {
using Base::Base;
};
constexpr char const str[] = "abc";
int main() {
Child<make_string_literal<decltype(str), str>::type> c(1, 1);
}
[live demo]

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...>;
// ...
}

How to extract a selected set of arguments of a variadic function and use them to call another function

I have a variadic function zoo which takes N arguments, where N is known at compile time (it is a template parameter of the class containing the function).
template <int N>
struct B
{
template <typename... Args>
static void zoo(Args... args)
{
static_assert(size of...(args) == N, "");
// do something
}
};
I have another variadic function foo which takes M arguments, where M>N and is known at compile time (it is a template parameter of the class containing the function). I have a static index_array containing the indices of the arguments of foo I want to pass to zoo.
From the body of foo I want to call zoo passing a selected subset of the arguments of foo.
What is the best way to do this? Ideally achieving perfect inlining, i.e. so that everything is compiled into just one instruction with no function pointers indirections?
template<int...I>
struct indices
{
static constexpr int N = sizeof...(I);
};
template <int M, typename...X>
struct A
{
// here I am simplifying, in reality IS will be built at compile time based on X
typedef indices<0,2,3> IS;
template <typename... Args>
static void foo(Args... args)
{
static_assert(size of...(args) == M, "");
// do some magic to achieve the function call described in pseudo-code
// B<IS::N>::zoo(args(IS(0),IS(1),IS(2)))
// ideally this should be perfectly inlined to just have the call above
}
};
Please note the code above is a simplification of my problem, designed for the purpose of illustrating the question.
EDIT:
As asked below, I describe the use case:
I am playing with a template based library to drive micro-controller pins. A micro controller has several ports (accessible as bytes in memory) and each port has up to 8 pins (bits). Class A is a bundle of pins via the template argument X, where every pin is defined as Pin. Class B manipulates all pins on the same port. A::foo is a function to modify some of the pins, with arguments in the same order as the order with which the pins are specified in the X template argument pack. foo needs to group the arguments by ports and dispatch to the B classes which representing individual ports, where all arguments are fused and written to the controller in a single instruction.
You can create a helper to extract the nth_arg like this:
template <int I>
struct ignore
{
template <typename T>
ignore(T&&) // This constructor accepts anything
{
}
};
template <typename T>
struct nth_arg;
template <size_t... DropIndexes>
struct nth_arg<std::integer_sequence<size_t, DropIndexes...>>
{
template <typename Arg, typename... Rest>
static decltype(auto) get(ignore<DropIndexes>..., // ignore args 0...n-1
Arg&& arg,
Rest&&...) // also ignore the rest
{
return std::forward<Arg>(arg); // return nth arg
}
};
And then call
template <int... Is, typename... Args>
static void call_zoo(indices<Is...>, Args&&... args)
{
B<sizeof...(Is)>::zoo(nth_arg<std::make_index_sequence<Is>>::get(
std::forward<Args>(args)...)...);
}
template <int M>
struct A
{
typedef indices<0, 2, 3> IS;
template <typename... Args>
static void foo(Args... args)
{
static_assert(sizeof...(args) == M, "");
call_zoo(IS{}, std::forward<Args>(args)...);
}
};
If you're using C++11, you can easily roll your own integer_sequence.
Pack the arguments into a tuple of references, and then retrieve them with std::get and a pack expansion on the indices.
template<class Tuple, int... Is>
static void magic(Tuple&& args, indices<Is...>){
B<IS::N>::zoo(std::get<Is>(std::forward<Tuple>(args))...);
}
template <typename... Args>
static void foo(Args... args)
{
static_assert(sizeof...(args) == M, "");
magic(std::forward_as_tuple(args...), IS{});
}
(You may want to make foo take forwarding references.)