How can I store the addresses of the arguments,
and make the function use them instead of the values it was initialized with?
This is not a running code, just the goal I would like to achieve.
class Class {
private:
Function function_; // e.g. : int Sum(int a, int b) { return a+b; } ;
std::tuple<Args...> args; // a,b provided are static consts.
public:
Class(Function _function, Args... _args) :
function_ { std::forward<Function>(_function) }
args{std::make_tuple( std::forward<Args>(_args)...) }
{}
void run_fucntion()
{
// use the addresses of a,b
function_( *p_a, *p_b ... ) // How do I do that?
}
You can use std::apply to apply the tuple of reference (not pointer but it do refer to the original object)
note: not sure what p_a and p_b supposed to be, but you can add then to the tuple with std::tuple_cat
#include <tuple>
template <typename F,typename ... Args>
class Class {
private:
F function;
std::tuple<Args...> args;
public:
Class(F&& function, Args&&... _args):
function(std::forward<F>(function)),
args{std::forward<Args>(_args)...}
{}
decltype(auto) run_fucntion()
{
return std::apply(function,args);
}
};
template <typename F,typename...Args>
Class(F&&,Args&&...) -> Class<F&&,Args&&...>;
auto f(int x){
return Class([](int a,int b){return a+b;},1,x).run_fucntion();
}
https://godbolt.org/z/jnY9sod94
if this is what you want, you can even pack them at first place
template <typename F,typename ... Args>
class Class {
private:
std::function<std::invoke_result_t<F,Args...>()> function;
public:
Class(F&& f, Args&&...args)
:function([&]{return std::forward<F>(f)(std::forward<Args>(args)...);}){}
decltype(auto) run_fucntion(){
return function();
}
};
template <typename F,typename...Args>
Class(F&&,Args&&...) -> Class<F&&,Args&&...>;
Related
I have a std::map where I store some arbitrary methods that I want to call later.
map<string, function<void(void)>> methods;
template<typename R, typename ...P>
void storeMethod(const string& name, const function<R(P...)>& method) {
methods[name] = method;
}
A the time of calling, I get the parameters to call the method with in a vector<void*>, where the first element is a pointer where I will store the return value.
How do I automatically cast these parameters to the corresponding types of the method I want to call?
Should I store the types in some way maybe?
void callMethod(const string& name, vector<void*> parameters) {
auto method = methods[name];
// How to call 'method' with all the parameters casted to the required types?
}
For example, if I orignally called storeMethod() with a function<int(string a, float b)>, I need a generic way to call it in callMethod() like this:
*((int*)parameters[0]) = method(*((string*)parameters[1]), *((float*)parameters[2]));
You will have to wrap method in something that can remember the parameter types.
struct OpaqueFunction {
virtual std::any call(const std::vector<std::any> &) = 0;
};
template <typename R, typename ... Args>
struct OpaqueFunctionImpl : OpaqueFunction {
OpaqueFunctionImpl(std::function<R(Args...)> f) : f(std::move(f)) {}
std::any call(const std::vector<std::any> & parameters) override {
return call_impl(parameters, std::index_sequence_for<Args...>{});
}
private:
template <size_t... I>
std::any call_impl(const std::vector<std::any> & parameters, std::index_sequence<I...>) {
return f(std::any_cast<Args>(parameters.at(I))...);
}
std::function<R(Args...)> f;
};
class Methods {
std::map<std::string, std::unique_ptr<OpaqueFunction>> methods;
public:
template<typename R, typename ... Args>
void storeMethod(std::string name, std::function<R(Args...)> method) {
methods[std::move(name)] = std::make_unique<OpaqueFunctionImpl<R, Args...>>(std::move(method));
}
template<typename R>
R callMethod(const std::string & name, const std::vector<std::any> & parameters) {
return std::any_cast<R>(methods.at(name)->call(parameters));
}
};
You can create a Callable type to functions that take different types of arguments and then, store that in a vector (using vector here for simplicity):
struct Callable {
Callable(std::function<void()> f) : zero_(std::move(f)) {}
Callable(std::function<void(int)> f) : one_(std::move(f)) {}
void operator()() { zero_(); }
void operator()(int x) { one_(x); }
std::function<void()> zero_;
std::function<void(int)> one_;
};
//vector of methods
std::vector<Callable> methods;
To store a method, you can either use a template-ized function or just use overloads. I am using overloads here:
void addMethod(std::function<void()> func)
{
methods.push_back(Callable(func));
}
void addMethod(std::function<void(int)> func)
{
methods.push_back(Callable(func));
}
And then to finally call a function:
template<typename ...Args>
void callMethod(int idx, Args ...args) {
auto method = methods[idx];
method(std::forward<Args>(args)...);
}
Main:
int main()
{
addMethod([](int x){
std::cout << "I am function(int)" << x << '\n';
});
addMethod([](){
std::cout << "I am just function()\n";
});
callMethod(0, 200);
callMethod(1);
}
This is the simplest possible way I can think of to achieve this. Their might be better ways and I am really curious about them.
Try it out here: https://godbolt.org/z/HS5a7p
I'm trying to write a class Invocation which has a templated constructor:
template<typename F>
class Invocation {
public:
template<typename... Args>
Invocation(F&& f, Args&&... args)
{ /* store f and args somewhere for later use */ }
...
};
Normally I would parameterize the Invocation class itself with both F and Args..., but in this case I need a uniform type for a given F, so I'm trying to find a way to store args... of any types inside a Invocation<F>, and to incur as little performance hit as possible. (This might not be the best design, but it can be an interesting exercise.)
One thought is to use virtual functions:
template<typename F>
class ArgsBase {
public:
// discard return value
virtual void invoke(F&& f) = 0;
};
template<typename F, typename... Ts>
class Args : public ArgsBase<F> {
public:
Args(Ts&&... args) : args_(std::forward<Ts>(args)...) {}
void invoke(F&& f) override
{
/* somehow call f with args_ (something like std::apply) */
...
}
private:
std::tuple<Ts&&...> args_;
};
And then in the Invocation<F> class, we can for example have an std::unique_ptr<ArgsBase<F>> member, which points to an Args<F, Ts...> object created in the Invocation<F> ctor. And we can call its invoke virtual method when needed.
This is just one random idea I came up with. Is there any other way to achieve this? Ideally without the overhead of virtual functions or anything like that?
UPDATE: Thanks to the comments/answers that suggest using std::function or lambdas. I should've made it clear that I'm actually interested in a more general case, i.e., the variadic stuff might not be arguments to a callable. It can be just anything that I want to store in a class whose type is not parameterized by the types of these stuff.
As mentioned in comment, I wouldn't worry about storing arguments by value. The compiler's copy-elision can be generous.
Particularly if you offer the class an r-value invoke:
#include <tuple>
template<typename F>
class ArgsBase {
public:
// discard return value
virtual void invoke(F&& f) const & = 0;
virtual void invoke(F&& f) && = 0;
};
template<typename F, class... FunctionArgs>
class Args : public ArgsBase<F> {
public:
template<class...Ts>
Args(Ts&&... args) : args_(std::forward<Ts>(args)...) {}
template<std::size_t...Is, class Tuple>
static void invoke_impl(F& f, std::index_sequence<Is...>, Tuple&& t)
{
f(std::get<Is>(std::forward<Tuple>(t))...);
}
void invoke(F&& f) const & override
{
invoke_impl(f,
std::make_index_sequence<std::tuple_size<tuple_type>::value>(),
args_);
/* somehow call f with args_ (something like std::apply) */
}
void invoke(F&& f) && override
{
invoke_impl(f,
std::make_index_sequence<std::tuple_size<tuple_type>::value>(),
std::move(args_));
/* somehow call f with args_ (something like std::apply) */
}
private:
using tuple_type = std::tuple<FunctionArgs...>;
tuple_type args_;
};
template<class Callable, class...MyArgs>
auto later(MyArgs&&...args) {
return Args<Callable, std::decay_t<MyArgs>...>(std::forward<MyArgs>(args)...);
}
void foo(const std::string&, std::string)
{
}
int main()
{
auto l = later<decltype(&foo)>(std::string("hello"), std::string("world"));
l.invoke(foo);
std::move(l).invoke(foo);
}
If you're trying to save a function call with its parameters for later invocation, you could use lambdas packaged in std::function objects:
template<typename F, typename ... Args>
std::function<void()> createInvocation(F f, const Args& ... args)
{
return [f,args...]() { f(args...); };
}
Then you could use it like this:
void myFunc(int a, int b)
{
std::cout << "Invoked: " << a + b << std::endl;
}
int main() {
auto invocation = createInvocation(myFunc, 1, 2);
invocation();
return 0;
}
UPDATE: If you wanted to create a generic non-templated container type, you can wrap a tuple into a type that itself derives from a non-templated type. The main problem then is accessing the underlying data. This can be solved by creating a static function dispatch table that for a given tuple type, redirects queries so that std::get, which requires a compile-time constant index template parameter, can instead be invoked with a dynamically provided function parameter. Here is an implementation that achieves this:
class GenericTupleContainer
{
public:
virtual const void* getItemAtIndex(size_t index) = 0;
};
template<typename ... T>
class TupleContainer : public GenericTupleContainer
{
public:
TupleContainer(T&& ... args)
: data(std::forward<T>(args)...)
{}
const void* getItemAtIndex(size_t index) override
{
if(index >= sizeof...(T))
throw std::runtime_error("Invalid index");
return dispatchTable[index](data);
}
private:
template<size_t index>
static const void* getItemAtIdx(const std::tuple<T...>& data)
{
return &std::get<index>(data);
}
using GetterFn = const void*(*)(const std::tuple<T...>&);
static GetterFn* initDispatchTable()
{
static GetterFn dispatchTable[sizeof...(T)];
populateDispatchTable<sizeof...(T)>(dispatchTable, std::integral_constant<bool, sizeof...(T) == 0>());
return dispatchTable;
}
static GetterFn* dispatchTable;
template<size_t idx>
static void populateDispatchTable(GetterFn* table, std::false_type);
template<size_t idx>
static void populateDispatchTable(GetterFn* table, std::true_type)
{
//terminating call - do nothing
}
std::tuple<T...> data;
};
template<typename ... T>
typename TupleContainer<T...>::GetterFn* TupleContainer<T...>::dispatchTable = TupleContainer<T...>::initDispatchTable();
template<typename ... T>
template<size_t idx>
void TupleContainer<T...>::populateDispatchTable(GetterFn* table, std::false_type)
{
table[idx-1] = &TupleContainer<T...>::template getItemAtIdx<idx-1>;
populateDispatchTable<idx-1>(table, std::integral_constant<bool, idx-1 == 0>() );
}
template<typename ... T>
auto createTupleContainer(T&& ... args)
{
return new TupleContainer<T...>(std::forward<T>(args)...);
}
Then you can use the above as follows:
int main() {
GenericTupleContainer* data = createTupleContainer(1, 2.0, "Hello");
std::cout << *(static_cast<const int*>(data->getItemAtIndex(0))) << std::endl;
std::cout << *(static_cast<const double*>(data->getItemAtIndex(1))) << std::endl;
std::cout << (static_cast<const char*>(data->getItemAtIndex(2))) << std::endl;
return 0;
}
As you can see from the above usage, you've achieved the aim of wrapping an arbitrary templated tuple into a non-templated type, in such a way that you can access the component members with a normal (function) index parameter instead of a template one. Now the return type of such a getter has to be universal, so I've chosen to use void* here, which is not ideal. But you can develop this idea to make this container give more useful information about the types of its data tuple members. Also, note that this does use a virtual function. With some further work you can get rid of this as well, although you won't be able to get rid of at least one function pointer lookup (i.e. the lookup in the dispatch table) - this is the price paid for gaining the flexibility of being able to use a runtime value to index into the tuple.
Context
I'm currently working on my own library for loading custom script inside c++ applications.
Here's some sample code for explaining what it's doing:
script part:
test.ctv
script
{
object player = access("player");
player.posX = 1 + 2;
access("map").load("map.txt");
}
C++ part:
test.cpp
class Player : public Loadable{
private:
friend class cTVScript::scriptExecutor;
primaryLoadable<int> posX;
stringLoadable name;
public:
Player() : Loadable(&posX, "posX", &name, "name");
}
class Map : public Loadable{
private:
friend class cTVScript::scriptExecutor;
std::string mapName;
public:
void load(std::string map) {
mapName = map;
}
Map() : Loadable(&load, "load") {}
}
int main() {
Player *p = new Player();
Map *m = new Map();
cTVScript::LoadScript("test.ctv");
cTVScript::AddObject(p, "player");
cTVScript::AddObject(m, "map");
std::cout << player.posX.get() << std::endl; // for example purpose we just assume that posX are public
std::cout << player.mapName.get() << std::endl; // same for mapName
}
Problem
Variable accessing and using by the cTVScript::scriptExecutor is quite simple,
but my main problem is elsewhere:
How, in c++, can I save and call method/functions with differents prototype?
Some trick with the compiler could make it easier? (like knowing the type and numbers of arguments?)
Current Work-Around
Make the user define a sub-fonction like AccessibleLoad:
class Map{
[...]
public:
void load(std::string map) {
mapName = map;
}
static void AccessibleLoad(cTVScript::CallingPack& pack) {
/* arguments */
std::string map;
pack.loadArguments(map); // here the user ask for each arguments
/*calling object */
Map* _this;
pack.loadCallingObject(_this); // and here he ask for the calling object
_this->load(map);
}
Map() : Loadable(&AccessibleLoad, "load") {}
}
So!
Is there a trick or some way i could make it more easy for using functions/methodes in my library? (like constructing these functions with the compiler? (don't think so but better to ask))
Edit
There's news! I got my own answer, and i'll post it (but it's a bit long)
(by the way, english is not my native language so if i made an error, said me so, i'll edit)
doing the C++ -> your script call. This is c++11 by the way
You will need some form of packer that can take a type and add it in.
class SomeClassYouCanCallAScriptFunction {
// the order of these templates matter or else
// the one bellow will not be able to find the one higher
template<class T, class... Args>
callFunction(string name){
// run your code to call your scripted function
// arguments has the arguments array
}
template<class T, class... Args>
callFunction(string name, T var){
// last one
// either this
arguments.pack<T>(var);
// or this
arguments.pack(to_string(var));
// or the like
// now do the next one
callFunction(name);
}
template<class T, class... Args>
callFunction(string name, T var, Args... args){
// either this
arguments.pack<T>(var);
// or this
arguments.pack(to_string(var));
// or the like
// now do the next one
callFunction(name, args...);
}
}
someClass.callFunction("scriptFunc", "ya", 42, someVectMaybe);
The otherway around the best you can do is provide a arguments variable and let the user get a argument passed in like arguments.get<T>(index)
Detail On the Context
For more Understanding (and if one want to re-use my solution), I'l detail the context of what i'm doing:
There's a top level (accessible only by the cTVScript::Executor)
And a low level (Visible (or almost) by the user)
top Level (or Non-typed part)
/*
* Non-Typed Part
*/
class Loadable{
public:
virtual std::string getAsString() { return ""; }
};
struct parametersPack{
public:
Loadable* returnValue;
std::vector<Loadable*> arguments;
};
Low Level (or typed-part)
class StringLoadable : public Loadable{
private:
std::string value;
public:
StringLoadable(std::string _s) : value(_s) {}
virtual std::string getAsString() { return value; }
virtual std::string get() { return value; }
virtual std::string& getRef() { return value; }
};
template<typename type>
class primaryLoadable : public Loadable{
private:
type value;
public:
primaryLoadable(type _v) : value(_v) {}
virtual std::string getAsString() { return std::to_string(value); }
type get() {return value;}
type& getRef() {return value;}
};
Save Function with non-matching prototype
A Parent Function Class (for stocking them):
class functionLoadable : public Loadable{
public:
virtual void call(parametersPack& pack) = 0;
};
And Sub-Function (one with void return and other with typed-Return)
/*
* Static Loadable Function
*/
template <typename Return, typename... Arguments>
class StaticLoadableFunction : public functionLoadable{
private:
Return (*fn)(Arguments...);
public:
Return calling(Arguments... args) {
Return value = fn(args...);
return (value);
}
virtual void call(parametersPack& pack) {
Unpacker::applyFunc(pack.arguments, fn);
}
StaticLoadableFunction(Return (*_fn)(Arguments...)) : fn(_fn){}
};
template <typename... Arguments>
class StaticLoadableFunction<void, Arguments...> : public functionLoadable{
private:
void (*fn)(Arguments...);
public:
void calling(Arguments... args) {
fn(args...);
}
virtual void call(parametersPack& pack) {
Unpacker::applyFunc(pack.arguments, fn);
}
StaticLoadableFunction(void (*_fn)(Arguments...)) : fn(_fn){}
};
Now the work of the unpacker
First I need to unpack my arguments from my std::vector
/*
* Unpacking all arguments
*/
template<unsigned int N>
struct helper;
template<unsigned int N>
struct helper{
template <typename ReturnType, typename... Arguments, typename ...final>
static ReturnType applyFunc(std::vector<Loadable*> parameters, ReturnType (*fn)(Arguments...), final&&... args) {
return (helper<N - 1>::applyFunc
(parameters, fn,
convertLoadableTo< typename parametersType<N - 1, Arguments...>::type >
::transform(parameters[N-1]),
args...));
}
};
template<>
struct helper<0>{
template <typename ReturnType, typename ...Arguments, typename ...final>
static ReturnType applyFunc(std::vector<Loadable*> parameters, ReturnType (*fn)(Arguments...), final&&... args) {
return (fn( args... ));
}
};
template <typename ReturnType, typename ...Arguments>
ReturnType applyFunc(std::vector<Loadable*> args, ReturnType (*fn)(Arguments...)) {
return (helper<sizeof...(Arguments)>::applyFunc(args, fn));
}
I know want to know wich type are in each recursion:
/*
* Getting Parameters type N in variadic Templates
*/
template <int N, typename... T>
struct parametersType;
template <typename T0, typename... T>
struct parametersType<0, T0, T...> {
typedef T0 type;
};
template <int N, typename T0, typename... T>
struct parametersType<N, T0, T...> {
typedef typename parametersType<N-1, T...>::type type;
};
And then downcast my Loadable* object into primaryLoadable<> or StringLoadable
/*
* Treat For Each Type
*/
template <typename arg>
struct convertLoadableTo;
template <typename arg>
struct convertLoadableTo{ // int, double...etc
static arg transform(Loadable* l) {
primaryLoadable<arg>* _l =
dynamic_cast< primaryLoadable<arg>* >(l);
if (!_l)
throw;
return (_l->get());
}
};
template <typename arg>
struct convertLoadableTo<arg&>{ // int&, double&...etc
static arg& transform(Loadable* l) {
primaryLoadable<arg>* _l =
dynamic_cast< primaryLoadable<arg>* >(l);
if (!_l)
throw;
return (_l->getRef());
}
};
template <>
struct convertLoadableTo<std::string>{ // int&, double&...etc
static std::string transform(Loadable* l) {
StringLoadable* _l =
dynamic_cast< StringLoadable* >(l);
if (!_l)
throw;
return (_l->get());
}
};
template <>
struct convertLoadableTo<std::string&>{ // int&, double&...etc
static std::string& transform(Loadable* l) {
StringLoadable* _l =
dynamic_cast< StringLoadable* >(l);
if (!_l)
throw;
return (_l->getRef());
}
};
That's the end!
If you wanna know more detail please mp me!
In relation with this question, that perhaps is too much oversimplified, I give here a more complex example. The problem that I pretend is depicted with the following code:
// test3.cpp
using namespace std;
template<typename T>
struct exer
{
template<typename R, typename... rArgs, typename... pArgs>
R operator()(R(T::*f)(rArgs...), pArgs&&... args)
{
return (t.*f)(forward<pArgs>(args)...);
}
T t;
};
struct A
{
int addition() { return 0; }
template<typename... Args>
int addition(int a, Args... args) { return a + addition(args...); }
};
struct B
{
public:
template<typename... Args>
int addition(Args&&... args)
{
return m_e(&A::addition, forward<Args>(args)...);
}
private:
exer<A> m_e;
};
int main()
{
B b;
cout << b.addition(1, 2, 3, 4) << endl;
}
This problem here is, in the instantation of B::addition, the type of &A::addition isn't known because different overloads exists. Moreover, B::addition doesn't know also which overload must be used. This doesn't know the compiler until the function is called. But, in order to correctly specify wich overload must be used in exer<A>::operator(), I need to make a casting of &A::addition to cast it to the correct overload.
How can I extract the type of the correct overload of the target function?
Change the question. If you can make exer take a callable object instead of a pointer to member function, like so:
template<typename T>
struct exer
{
T t;
template<typename F, typename... pArgs>
auto operator()(F f, pArgs&&... args)
-> decltype(f(t, forward<pArgs>(args)...))
{
return f(t, forward<pArgs>(args)...);
}
};
Then you can do this instead:
struct B
{
public:
template<typename... Args>
int addition(Args&&... args)
{
struct Invoker {
auto operator()(A& a, Args&&... args) const
->decltype(a.addition(std::forward<Args>(args)...))
{ return a.addition(std::forward<Args>(args)...); }
};
return m_e(Invoker(), forward<Args>(args)...);
}
private:
exer<A> m_e;
};
Now selecting the correct A::addition is done by the compiler using the normal overload resolution rules.
Instead of Invoker you could use a lambda expression, which reduces some of the repetition:
return m_e( [](A& a, Args&&... as) {
return a.addition(forward<Args>(as)...);
},
forward<Args>(args)...);
Consider this code:
#include <iostream>
using namespace std;
class hello{
public:
void f(){
cout<<"f"<<endl;
}
virtual void ff(){
cout<<"ff"<<endl;
}
};
#define call_mem_fn(object, ptr) ((object).*(ptr))
template<R (C::*ptr_to_mem)(Args...)> void proxycall(C& obj){
cout<<"hello"<<endl;
call_mem_fn(obj, ptr_to_mem)();
}
int main(){
hello obj;
proxycall<&hello::f>(obj);
}
Of course this won't compile at line 16, because the compiler doesn't know what R, C and Args, are. But there's another problem: if one tries to define those template parameters right before ptr_to_mem, he runs into this bad situation:
template<typename R, typename C, typename... Args, R (C::*ptr_to_mem)(Args...)>
// ^variadic template, but not as last parameter!
void proxycall(C& obj){
cout<<"hello"<<endl;
call_mem_fn(obj, ptr_to_mem)();
}
int main(){
hello obj;
proxycall<void, hello, &hello::f>(obj);
}
Surprisingly, g++ does not complain about Args not being the last parameter in the template list, but anyway it cannot bind proxycall to the right template function, and just notes that it's a possible candidate.
Any solution? My last resort is to pass the member function pointer as an argument, but if I could pass it as a template parameter it would fit better with the rest of my code.
EDIT:
as some have pointed out, the example seems pointless because proxycall isn't going to pass any argument. This is not true in the actual code I'm working on: the arguments are fetched with some template tricks from a Lua stack. But that part of the code is irrelevant to the question, and rather lengthy, so I won't paste it here.
You could try something like this:
template <typename T, typename R, typename ...Args>
R proxycall(T & obj, R (T::*mf)(Args...), Args &&... args)
{
return (obj.*mf)(std::forward<Args>(args)...);
}
Usage: proxycall(obj, &hello::f);
Alternatively, to make the PTMF into a template argument, try specialization:
template <typename T, T> struct proxy;
template <typename T, typename R, typename ...Args, R (T::*mf)(Args...)>
struct proxy<R (T::*)(Args...), mf>
{
static R call(T & obj, Args &&... args)
{
return (obj.*mf)(std::forward<Args>(args)...);
}
};
Usage:
hello obj;
proxy<void(hello::*)(), &hello::f>::call(obj);
// or
typedef proxy<void(hello::*)(), &hello::f> hello_proxy;
hello_proxy::call(obj);
In modern C++ one can use template<auto> and generic lambda-wrapper:
#include <utility>
#include <functional>
template<auto mf, typename T>
auto make_proxy(T && obj)
{
return [&obj] (auto &&... args) { return (std::forward<T>(obj).*mf)(std::forward<decltype(args)>(args)...); };
}
struct R {};
struct A {};
struct B {};
struct Foo
{
R f(A &&, const B &) { return {}; }
//R f(A &&, const B &) const { return {}; }
};
int main()
{
Foo foo;
make_proxy<&Foo::f>(foo)(A{}, B{});
//make_proxy<static_cast<R (Foo::*)(A &&, const B &) const>(&Foo::f)>(std::as_const(foo))(A{}, B{});
//make_proxy<static_cast<R (Foo::*)(A &&, const B &)>(&Foo::f)>(foo)(A{}, B{});
}
If there are overloadings one should to specify member function type explicitly as in commented code.