How to Store Variadic Template Arguments

How to store variadic template arguments?

To accomplish what you want done here, you'll have to store your template arguments in a tuple:

std::tuple<Ts...> args;

Furthermore, you'll have to change up your constructor a bit. In particular, initializing args with an std::make_tuple and also allowing universal references in your parameter list:

template <typename F, typename... Args>
Action(F&& func, Args&&... args)
: f(std::forward<F>(func)),
args(std::forward<Args>(args)...)
{}

Moreover, you would have to set up a sequence generator much like this:

namespace helper
{
template <int... Is>
struct index {};

template <int N, int... Is>
struct gen_seq : gen_seq<N - 1, N - 1, Is...> {};

template <int... Is>
struct gen_seq<0, Is...> : index<Is...> {};
}

And you can implement your method in terms of one taking such a generator:

template <typename... Args, int... Is>
void func(std::tuple<Args...>& tup, helper::index<Is...>)
{
f(std::get<Is>(tup)...);
}

template <typename... Args>
void func(std::tuple<Args...>& tup)
{
func(tup, helper::gen_seq<sizeof...(Args)>{});
}

void act()
{
func(args);
}

And that it! So now your class should look like this:

template <typename... Ts>
class Action
{
private:
std::function<void (Ts...)> f;
std::tuple<Ts...> args;
public:
template <typename F, typename... Args>
Action(F&& func, Args&&... args)
: f(std::forward<F>(func)),
args(std::forward<Args>(args)...)
{}

template <typename... Args, int... Is>
void func(std::tuple<Args...>& tup, helper::index<Is...>)
{
f(std::get<Is>(tup)...);
}

template <typename... Args>
void func(std::tuple<Args...>& tup)
{
func(tup, helper::gen_seq<sizeof...(Args)>{});
}

void act()
{
func(args);
}
};

Here is your full program on Coliru.


Update: Here is a helper method by which specification of the template arguments aren't necessary:

template <typename F, typename... Args>
Action<Args...> make_action(F&& f, Args&&... args)
{
return Action<Args...>(std::forward<F>(f), std::forward<Args>(args)...);
}

int main()
{
auto add = make_action([] (int a, int b) { std::cout << a + b; }, 2, 3);

add.act();
}

And again, here is another demo.

How to Store Variadic Template Arguments Passed into Constructor and then Save them for Later Use?

Since run will return void, I assume all the functions you need to wrap can be functions that return void too.
In that case you can do it like this (and let lambda capture do the storing for you):

#include <iostream>
#include <functional>
#include <string>
#include <utility>

class FnWrapper
{
public:
template<typename fn_t, typename... args_t>
FnWrapper(fn_t fn, args_t&&... args) :
m_fn{ [=] { fn(args...); } }
{
}

void run()
{
m_fn();
}

private:
std::function<void()> m_fn;
};

void foo(const std::string& b)
{
std::cout << b;
}

int main()
{
std::string hello{ "Hello World!" };
FnWrapper wrapper{ foo, hello };
wrapper.run();
return 0;
}

Store variadic template arguments and pass them to lambda

I'm getting some good mileage out of that parameter-detection code :)

Let's get this done first -- we want to get a list of parameter types from the type of whatever we passed to magicTemplate:

namespace glk {
namespace tmp {
template <class T>
struct type_is {
using type = T;
};

template <class...>
using void_t = void;

// Pack of arbitrary types
template <class...>
struct pack { };

namespace detail_parameters {
template <class F, class = void_t<>>
struct parameters { };

template <class F>
struct parameters<F, void_t<decltype(&F::operator ())>>
: parameters<decltype(&F::operator ())> { };

template <class R, class... Params>
struct parameters<R(Params...)> : type_is<pack<Params...>>{ };

template <class R, class... Params>
struct parameters<R(*)(Params...)> : type_is<pack<Params...>>{ };

template <class T, class R, class... Params>
struct parameters<R(T::*)(Params...)> : type_is<pack<Params...>>{ };

template <class T, class R, class... Params>
struct parameters<R(T::*)(Params...) const> : type_is<pack<Params...>>{ };
}

// Retrieve the parameter list from a functionoid
template <class F>
using parameters = typename detail_parameters::parameters<
std::remove_reference_t<F>
>::type;
}
}

Now glk::tmp::parameters<F> gives us a glk::tmp::pack<T...> where each T corresponds to a parameter. Now, let's suppose we have that, and implement the actual body of magicTemplate:

template <std::size_t FmtSize, class AndThen, class... Args, std::size_t... ArgsIdx>
void magicTemplate(
char const (&fmt)[FmtSize], AndThen &&andThen,
glk::tmp::pack<Args...>,
std::index_sequence<ArgsIdx...>
) {
std::array<char, FmtSize + 1> fmtStr;
fmtStr[0] = 'O';
std::copy(fmt, fmt + FmtSize, fmtStr.data() + 1);

std::tuple<Args...> args;
std::scanf(fmtStr.data(), &std::get<ArgsIdx>(args)...);

std::forward<AndThen>(andThen)(std::get<ArgsIdx>(args)...);
}

(I have replaced extractArgs with std::scanf for testing purposes, since they seem to be quite similar)

Now just a bit of plumbing to actually produce the required std::index_sequence:

template <std::size_t FmtSize, class AndThen, class... Args>
void magicTemplate(
char const (&fmt)[FmtSize], AndThen &&andThen,
glk::tmp::pack<Args...>
) {
return magicTemplate(
fmt, std::forward<AndThen>(andThen),
glk::tmp::pack<Args...>{},
std::index_sequence_for<Args...>{}
);
}

template <std::size_t FmtSize, class AndThen>
void magicTemplate(char const (&fmt)[FmtSize], AndThen &&andThen) {
return magicTemplate(
fmt, std::forward<AndThen>(andThen),
glk::tmp::parameters<AndThen>{}
);
}

Et voilà! We can call this thing with the exact syntax you wished for. Of course, everything looking remotely like error checking has been left as an exercise for the reader :)

Live demo on Coliru

How does std::thread store variadic arguments passed through its constructor?

I am basically trying to implement my own version of std::function, for my own edification. I am curious how in C++ you would go about storing a function with a bunch of arbitrary parameters inside an object, and then having a method that would call the function with the passed in arguments.

std::function is a beast of a class so I won't pretend that this is anywhere close to as complete. std::function uses type erasure and small object optimization but I'll use polymorphism and store a base class pointer to a semi-anonymous implementation of a function wrapper to show how it can be done. I say semi-anonymous because it actually has a name, but it's defined locally inside the function that instantiates it. Storing the pointer (or the empty state) will be done in a std::unique_ptr<funcbase>.

The goal, as I've understood it, is to create a class with this basic interface:

template <class R, class... Args>
class fn_with_args<R(Args...)> {
public:
template <class F> fn_with_args(F&& f, Args&&... args);
R operator()();
};

That is, we need instances of fn_with_args<R(Args...)> to be able to store function pointers / functors that when invoked with the stored arguments returns R.

#include <functional>
#include <memory>
#include <tuple>

template <class> class fn_with_args; // not implemented

template <class R, class... Args>
class fn_with_args<R(Args...)> {
// an abstract base for cloneable function objects with an operator()() to call
struct funcbase {
virtual ~funcbase() = default;
virtual std::unique_ptr<funcbase> clone() const = 0;
virtual R operator()() = 0;
};

public:
// create empty "fn_with_args":
fn_with_args() noexcept = default;
fn_with_args(std::nullptr_t) noexcept {};

// copy ctor - if store contains a pointer to a funcbase,
// let it clone itself
fn_with_args(const fn_with_args& other) :
store(other.store ? other.store->clone() : nullptr) {}

// copy assignment
fn_with_args& operator=(const fn_with_args& other) {
if(this != &other) *this = fn_with_args(other); // copy+move
return *this;
}

// moving can be done by default:
fn_with_args(fn_with_args&& other) noexcept = default;
fn_with_args& operator=(fn_with_args&& other) noexcept = default;

// constructing and storing arguments
template <class F>
fn_with_args(F&& f, Args&&... args) {
// the semi-anonymous implementation that inherits from funcbase
// and stores both the function and the arguments:
struct funcimpl : funcbase {
funcimpl(F&& f, Args&&... a)
: func{std::forward<F>(f)}, args{std::forward<Args>(a)...} {}

// cloning via a base class pointer:
std::unique_ptr<funcbase> clone() const override {
return std::make_unique<funcimpl>(*this);
}

// the operator that will call `func` with the stored arguments:
R operator()() override { return std::apply(func, args); }

F func; // the actual function/functor
std::tuple<Args...> args; // and the stored arguments
};

// create and store an instance of the above semi-anonymous class:
store = std::make_unique<funcimpl>(std::forward<F>(f),
std::forward<Args>(args)...);
}

// The call interface. It'll dereference `store` and then call it which
// will call the overridden operator()() in the semi-anonymous `funcimpl`:
R operator()() {
if(store) return (*store)();
throw std::bad_function_call();
}

private:
std::unique_ptr<funcbase> store;
};

Example usage:

#include <iostream>

double foo(int x) {
return x * 3.14159;
}

int main() {
fn_with_args<int(double)> f1([](double d) -> int { return d; }, 3.14159);
std::cout << f1() << '\n';

fn_with_args<void()> f2; // create empty
//f2(); // would throw "bad_function_call" since it is "empty"

// populate it
f2 = fn_with_args<void()>([]{ std::cout << "void\n"; });
f2();

// call regular function:
fn_with_args<double(int)> f3(foo, 2);
std::cout << f3() << '\n';

// example with capture:
int v = 123;
f1 = fn_with_args<int(double)>([v](double d) -> int { return v * d; }, 3.14159);
std::cout << f1() << '\n';

// copying:
auto f11 = f1;
std::cout << f11() << '\n'; // calling the copy
}

Demo

How to store variadic template parameters in c++ ?

You can write a helper function that unpacks std::integer_sequence,

template<int... is>
auto make_printer_impl(std::integer_sequence<int, is...>)
{
Printer<is...> printer;
return printer;
}

template<class T>
auto make_printer()
{
return make_printer_impl(typename T::_Ni{});
}

and then use it like this:

auto TestPrinterSpecialSequence = make_printer<SpecialClass>();
TestPrinterSpecialSequence.print();

You can do the similar thing for std::array member:

template<class T, std::size_t... is>
auto make_printer_impl(std::index_sequence<is...>)
{
Printer<T::_N[is]...> printer;
return printer;
}

template<class T>
auto make_printer()
{
return make_printer_impl<T>(std::make_index_sequence<T::_N.size()>{});
}

Also note that identifiers that begin with an underscore followed by an uppercase letter are reserved. Their usage leads to the undefined behavior. Don't use them.

Storing arguments in a variadic template function without using boost::any

You could use std::common_type, e.g.:

template <class Var, class... Args>
void CPP_FOR(Var *variable, uint32_t numParams, Args... args)
{
std::vector<std::common_type_t<Args...>> arguments{args...};
// do stuff with arguments
}

You can also remove numParams and the runtime check because this will fail at compile time if there is no common type. And if you only want to iterate over the arguments, a vector is maybe overkill... so something like:

template <class Var, class... Args>
void CPP_FOR(Var *variable, Args... args)
{
std::common_type_t<Args...> arguments[]{args...};
for(size_t i = 0; i < sizeof...(Args); ++i)
variable[i] = /* ... */;
}

Note that both of these will fails if sizeof... (Args) is 0, i.e. you are calling with only a Var* - You may want to handle this case separately if necessary.

Is it possible to store variadic arguments into a member variable?

Assuming I read your mind right, you save the args by not saving the args.

First, write this:

void DoOperation( std::tuple<int, double, std::string> const& tup ) {
auto&& some_arg_name = std::get<0>(tup);
auto&& second_arg_name = std::get<1>(tup);
// etc
// do stuff with the args
}

typedef std::function<void(TempClass*)> saved_operation;

saved_operation BuildOperation( int a, double b, std::string s ) const {
auto tup = std::make_tuple(a,b,s);
return [tup](TempClass* self){
return self->DoOperation(tup);
};
}

DoOperation takes a tuple, and does the operation using those arguments.

BuildOperation takes arguments, bundles them into a tuple, and generates a saved_operation from them.

saved_operation is basically a saved method call. I don't store this because by avoiding that, the default copy ctor does the right thing. Instead, you pass this in each time you use it.

Now using the above, we implement your stuff:

saved_operation saved_op;

template<typename ...Args>
void SaveTheseArgs(args&& ...args)
{
saved_op = BuildOperation(std::forward<Args>(args)...);
saved_op(this);
}

void OtherMethod()
{
assert(saved_op);
saved_op(this);
}

A copy of the tuple is actually stored inside the saved_operation object, but that is an implementation detail.

The trick is we care not about the data, but rather what we will do with the data later.

I used some concrete types (the int double etc), but those can just as easily be template methods as well.

If you need the efficiency, a bit more care involving moving data around instead of copying can be useful. But I kept it relatively simple. If you really need a pack of any args, you might have to google the "indexes trick" to unpack the tuple of unknown content back into parameters.

In this case, std::function is a type erasure class that erases the details of what it is constructed from, except for the fact it can be copied, destroyed, invoked with a particular signature (and also cast-back-to-source-type, which few people use).

We exploit this to "forget" the tuple and instead just remember the operation we want to do on the tuple.

This technique can be used in more general situations: you can type erase anything with a fixed signature, or really anything that can be boiled down to a fixed signature (which is a bit broader).

Words to search for for more on this topic include "runtime concepts" and "type erasure". Examining how std::function can be implemented.

Most efficient way to store variadic function template arguments into a union vector?

You can initialize _data directly.

template<typename... Ts>
DataStore(Ts... ts) : _data{ts...}
{}

Store variadic arguments in class template

I suggest you some corrections

(1) in MemberTask, the definition of the Method type should include the arguments of the method; so, instead of

typedef ReturnType(Class::*Method)();

you should write

typedef ReturnType(Class::*Method)(Types...);

(2) in CreateSimpleTask(), instead of

return new SimpleTask<
std::result_of<decltype(func)(Arguments...)>::type,
Arguments...>(std::forward<Function>(func), std::forward<Arguments>(args)...);

you should add a typename before std::result_of, so

return new SimpleTask<
typename std::result_of<decltype(func)(Arguments...)>::type,
Arguments...>(std::forward<Function>(func), std::forward<Arguments>(args)...);

(3) in CreateMemberTask() you have forgotten the typename and the arguments of the method; so, instead of

return new MemberTask<
std::result_of<decltype(method)(Class)>::type,
Class, Arguments...>(std::forward<Class*>(obj), std::forward<Method>(method),
std::forward<Arguments>(args)...);

you should write

return new MemberTask<
typename std::result_of<decltype(method)(Class, Arguments...)>::type,
Class, Arguments...>(std::forward<Class*>(obj), std::forward<Method>(method),
std::forward<Arguments>(args)...);


Related Topics



Leave a reply



Submit