I am currently in the process of writing a method execution queue in C++x0. I have implemented and verified the basic queue mechanism but want to amend it with an option to have push() automatically remove all previous calls to a specific method:
queue.push(this, &Obj::foo, 1);
queue.push(this, &Obj::foo, 2);
queue.push(this, &Obj::foo, 3);
should be the same as merely calling
queue.push(this, &Obj::foo, 3);
My code thus far looks like this:
Queue.h:
#pragma once
#include <functional>
#include <vector>
using std::vector;
using std::function;
using std::bind;
class Queue
{
private:
struct functioncall {
std::function<void()> call;
};
vector<functioncall> queue;
public:
Queue();
~Queue();
template<typename T, typename F, typename... Args>
int push(T, F , Args... args);
int pop();
bool empty();
size_t size();
};
template<typename T, typename F, typename... Args>
int Queue::push(T instance, F func, Args... args)
{
functioncall newelem = { bind(func, instance, args...) };
queue.push_back(newelem);
return queue.size();
}
Queue.cpp:
#include "Queue.h"
Queue::Queue() : queue()
{
}
Queue::~Queue()
{
delete &queue;
}
int Queue::pop()
{
if(!queue.empty())
{
queue.front().call();
queue.erase(queue.begin());
return queue.size();
}
return 0;
}
bool Queue::empty()
{
return queue.empty();
}
size_t Queue::size()
{
return queue.size();
}
I have already prepared the vector queue to take a struct in wich I want to not only save the result of std::bind but also the pointer to the method being called so I can look for that pointer and remove the old entries.
The issue is that the functions passed to push() can take an arbitrary amount of arguments. Is there a generic pointer type (it doesn't have to be executable, just be the same when I repeatedly push the same function to the queue) that can do that?
Per 5.2.10p10, you can cast a pointer to member function T::*(A1, A2, ...) to another pointer to member function type U::*(B1, ...) and back with no loss of information; std::less can compare pointers to member functions so by casting to a dummy pointer-to-member type void (Impl::*)() you can compare pointer to member functions with the same signature.
However, it is not guaranteed that pointer to member functions with different signatures will compare different when cast to the same pointer to member type, so you will need to encode the signature in your comparable type. typeid will work here:
auto key = std::make_pair(&typeid(F), reinterpret_cast<void (Queue::*)()>(func));
This assumes that F is indeed a pointer to member function; if the user attempts to pass some other callable object then this will break.
std::function::target<>() can be used to check wrapped function type:
template <class F> bool is_same_call(const functionalcall& prevCall, F newCall)
{
const F* pf = prevCall.call.target<F>();
return pf ? *pf == newCall : false;
}
Note that std::function::target() will return nullptr if function wrapped with std::function object has type different from F.
Related
I've been trying to expand a non value parameter pack recently in C++. Is this possible? And if it's not, why?
I mean, as you can see, in the line with the comment //, given a parameter pack for the TypeMap class, how can I call addType<T>() with each type of the parameter pack? Thanks in advance!
template <typename... T>
class TypeMap
{
using vari_cmps = std::variant<T*...>;
private:
template<typename Type>
void addType()
{
typemap[typeid(Type).name()] = std::make_unique<Type>(0).get();
}
public:
std::map<const char*, vari_cmps> typemap{};
TypeMap()
{
(addType<T,...>()); // Idk how to use this in order to make it work
}
~TypeMap()
{
typemap.clear();
}
};
As #HolyBlackCat has already answered in the comments, you can expand it like this:
TypeMap() {
(addType<T>(), ...);
}
If T is std::string, int, float this would expand to:
TypeMap() {
(addType<std::string>(), addType<int>(), addType<float>());
}
There are however a few more issues in this code-snippet:
1. addType()
addType() will not work as you'd expect, due to the unique_ptr deleteing your object after you put it into the map.
.get() only retrieves the pointer that the unique_ptr manages but does not transfer ownership, so the unique_ptr will still delete the pointed-to object once it gets out of scope, leaving a dangling pointer in your map.
so your addType() is roughly equivalent to:
template<typename Type>
void addType() {
Type* tptr = new Type(0); // unique pointer constructs object
typemap[typeid(Type).name()] = tptr; // insert pointer value of unique pointer
delete tptr; // unique pointer destructs
}
You could fix this by releasing the unique_ptr after inserting its value into the map & then cleaning it up in the destructor:
template<typename Type>
void addType() {
auto ptr = std::make_unique<Type>(0);
typemap[typeid(Type).name()] = ptr.get();
ptr.release(); // now unique_ptr won't delete the object
}
~TypeMap() {
// cleanup all pointers
for(auto& [name, ptrVariant] : typemap)
std::visit([](auto ptr) { delete ptr; }, ptrVariant);
}
2. Consider using std::type_index instead of const char* as map key
std::type_info::name() returns an implementation-defined name for the given type, so you have no guarantee that you will get an unique name for a given type.
Returns an implementation defined null-terminated character string containing the name of the type. No guarantees are given; in particular, the returned string can be identical for several types and change between invocations of the same program.
std::type_index on the other hand is build specifically for this purpose - using types as keys - and comes with all comparison operators & a std::hash specialization, so you can use it with std::map & std::unordered_map out of the box.
e.g.:
template <class... T>
class TypeMap
{
using vari_cmps = std::variant<T*...>;
private:
template<typename Type>
void addType()
{
typemap[std::type_index(typeid(Type))] = /* something */;
}
public:
std::map<std::type_index, vari_cmps> typemap{};
TypeMap() { /* ... */ }
~TypeMap() { /* ... */ }
template<class U>
U* get() {
auto it = typemap.find(std::type_index(typeid(U)));
return std::get<U*>(it->second);
}
};
Consider using std::tuple
std::tuple is basically built for this task, storing a list of arbitrary types:
e.g.:
template <class... T>
class TypeMap
{
private:
std::tuple<std::unique_ptr<T>...> values;
public:
TypeMap() : values(std::make_unique<T>(0)...) {
}
template<class U> requires (std::is_same_v<U, T> || ...)
U& get() { return *std::get<std::unique_ptr<U>>(values); }
template<class U> requires (std::is_same_v<U, T> || ...)
U const& get() const { return *std::get<std::unique_ptr<U>>(values); }
};
usage:
TypeMap<int, double, float> tm;
tm.get<int>() = 12;
If you want you can also store T's directly in the tuple, avoiding the additional allocations.
I'm working on a class that schedules functions by binding them in a queue like this:
std::queue <void()> q;
template<typename R,typename... ArgsT>
void
schedule(R& fn, ArgsT&... args)
{
q.push(std::bind(fn, std::forward<ArgsT>(args)...) );
};
template<typename R,typename... ArgsT>
void
schedule(R&& fn, ArgsT&&... args)
{
q.push(std::bind(fn, std::forward<ArgsT>(args)...) );
};
As you see I made the type in the queue void() to make it hold any type of function objects but now I can't get the return when I execute it. What should I do to solve this?
Note: I don't want to use an external library like boost and I don't know what kind of function the user will pass it.
Note: I don't want to use an external library like boost and I don't
know what's the kind of function the user will pass it.
What I usually do in this case is I use a base class (from Command pattern) in my queue, and then have two implementations, the one wrapping the bind, and the other (also wrapping the bind) exposing a function that allows getting the return value.
Here is an example of the returning specialization (at last):
#include <iostream>
#include <functional>
#include <memory>
struct ACmd
{
virtual void exec() = 0;
virtual ~ACmd(){}
};
template <class F>
struct Cmd;
template <class R, class ... Args>
struct Cmd<R(Args...)> : ACmd
{
R result_;
std::function<R()> func_;
template <class F>
Cmd(F&& func, Args&&... args): result_(), func_()
{
auto f = std::bind(std::forward<F>(func), std::forward<Args>(args)...);
func_ = [f](){
return f();
};
}
virtual void exec(){
result_ = func_();
}
const R& getResult() const {return result_;}
};
// Make function for convenience, could return by value or ptr -
// - your choice
template <class R, class F, class ...Args>
Cmd<R(Args...)>* cmd(F&& func, Args&&... args)
{
return new Cmd<R(Args...)>(func, std::forward<Args>(args)...);
}
//... And overload for void...
int foo(int arg) {
return arg;
}
int main() {
auto x = cmd<int>(foo, 10);
x->exec();
std::cout << x->getResult() << std::endl;
return 0;
}
The result of the execution of each element in the queue, it is void, you have already defined it as such. If the functions passed in are required to return a value, then you would need to limit the type(s) returned to a fixed type, use utilities such as std::any, std::variant or some covariant types (possible with a std::unique_ptr or std::shared_ptr).
The simplest is to fix the return type (at compile time);
template <typename R>
using MQ = std::queue<std::function<R()>>;
MQ<int> q;
See the sample below.
The queue declaration needs to be a queue of objects, such as std::function objects. The return value from a bind can be assigned to a function and then used as expected.
std::function is a polymorphic function wrapper, it implements type erasure patterns akin to any, but is specifically designed for functions and other callable objects.
By way of example;
template <typename R>
using MQ = std::queue<std::function<R()>>;
MQ<int> q;
template<typename R,typename... ArgsT>
void
schedule(R&& fn, ArgsT&&... args)
{
q.push(std::bind(std::forward<R>(fn), std::forward<ArgsT>(args)...) );
};
int main()
{
schedule([](int a) { std::cout << "function called" << std::endl; return a; }, 42);
std::cout << q.front()() << std::endl;
}
I am doing some magic with templates in c++ and thought of trying something.
In this case I wrote a naive generic list implementation with a List Type and a ListElement Type that contains the data.
Now I already wrote a templated "for each call" function, that takes an arbitrary member function type of the type stored in the list with an arbitrary argument list and calls that member function on each element in the list with the given arguments:
template<typename function, typename ... arguments>
void for_each_call(function call, arguments ... args)
{
for(ListElement * current = this->first; current != nullptr; current = current->next)
{
(current->value->*call)(args ...);
}
}
The problem with this is that I can not "react" to the return values of the called function. Though I do NOT want to implement a .map functionality!
Now I want to implement a "for each call until" that calls a function upon the values in the list until a call returns "true" and then stops. For that I need to limit the functions inserted as a template parameter to functions of any type that specifically return a boolean. I typed around until the compiler stopped complaining and got this:
template<bool (*function), typename ... arguments>
void for_each_call_until(arguments ... args)
{
for(ListElement * current = this->first; current != nullptr; current = current->next)
{
if((current->value->*function)(args ...)) break;
}
}
What is happening here, is this the right way, and if not, what is the right way?
EDIT: As some people recommend using functions from the std:: namespace: In these little training sessions I try to avoid the std:: like a plague, as if I would want to use std:: I would not write these little standardimplementations of stuff like lists, vectors or mappings myself but use std:: or boost::
First of all, this approach is unnecessarily limiting:
(current->value->*call)(args ...);
If you require a member function, there's only a small handful of operations you can actually do. If the caller wants to do more, they're kind of screwed. Instead, generalize and pass current->value as the first argument:
template<typename function, typename ... arguments>
void for_each_call(function call, arguments ... args)
{
for(ListElement * current = this->first; current != nullptr; current = current->next)
{
call(current->value, args...);
}
}
This works on all the cases as before - where you would pass &Class::mem before now instead you pass std::mem_fn(&Class::mem) - but now you can pass any kind of callable too.
Now onto your main question. You don't have to do anything different. Just use the result of call():
template<typename function, typename ... arguments>
void for_each_call(function call, arguments ... args)
{
for(ListElement* current = this->first; current != nullptr; current = current->next)
{
if (call(current->value, args...)) {
break;
}
}
}
That's it. If the user provides a callable that doesn't return something contextually convertible to bool, they'll get a compile error. Why limit to just returning bool?
If you really do need really just bool, throw in a static assert:
template<typename function, typename ... arguments>
void for_each_call(function call, arguments ... args)
{
static_assert(std::is_same<decltype(call(this->first->value, args...)), bool>::value, "Must be bool!");
// rest...
}
Note: You probably want to take your arguments... by reference to const to avoid lots of copies.
Starting from this, just to show you how member function pointers work:
class Foo {
public:
bool test() { return true; }
};
/// The function takes a member function of a class T and its arguments.
template<typename T, typename... Args>
void for_each_call_until(bool (T::*member_function)(Args...),
Args&& ... args) {
T obj; // Instantiate an example object.
bool rts = (obj.*member_function)(std::forward<Args>(args)...);
if (rts == false) { // Check for the result of the member function
// close
}
// ...
}
Your function could be something like:
template<typename... Args>
void for_each_call_until(bool (ListElement::*member_function)(Args...),
Args&& ... args) {
for ( /* iteration over pointers */ ) {
bool rts = (current->*member_function)(std::forward<Args>(args)...);
if (rts == false) {
// break
}
// ...
}
}
A simple solution involves using partial specialization to force a compilation error:
#include <type_traits>
#include <utility>
template<typename T> struct is_bool;
template<> struct is_bool<bool> { typedef int value; };
template<typename function, typename ... arguments>
void for_each_call(function call, arguments && ... args)
{
typedef decltype(call(std::forward<arguments>(args)...)) ret_type;
typedef typename is_bool<ret_type>::value x;
call(std::forward<arguments>(args)...);
}
bool foo(int, int) {} // Compiles
// int foo(int, int) {} // Does not compile
int main()
{
for_each_call(foo, 4, 2);
return 0;
}
I've been trying to come up with a templated function that generalizes the bounce procedure when dealing with C APIs that use function pointer callbacks.
I've mostly figured it out and have a working system, but I'm wondering if there is a way to clean up the final step.
Imagine you have an API that takes a function pointer and a user data pointer. You want to use an instance method as the callback target. This requires a "bounce" function that reinterprets the user data pointer as an instance pointer and calls the method with the rest of the arguments.
The following example code works:
#include <cstdio>
class Foo {
public:
Foo(int val) : val_(val) { }
void baz(int v) const
{
printf("baz %d\n", v + val_);
}
private:
int val_;
};
// Templated bounce function
template<class T, class Method, Method m, class Ret, class ...Args>
static Ret bounce(void *priv, Args... args)
{
return ((*reinterpret_cast<T *>(priv)).*m)(args...);
}
#define BOUNCE(c, m) bounce<c, decltype(&c::m), &c::m>
// Callback simulator
void call_callback(void (*func)(void *, int), void *priv, int v)
{
if (func) {
func(priv, v);
}
}
// Main Entry
int main()
{
Foo bar(13);
call_callback(&bounce<Foo, decltype(&Foo::baz), &Foo::baz>, &bar, 10);
call_callback(&BOUNCE(Foo, baz), &bar, 11);
return 0;
}
Basically I'm looking for a way to clean up the usage. The macro works but I'm trying to instead find some type of helper function that can just take a method pointer parameter like &Foo::baz and deduce all the parameters. Something like a bounce_gen(&Foo::baz) that would return a pointer to the actual bounce function.
It has been a fun exercise, but I can't quite get the last piece.
The type of a member function pointer contains the class type and the function signature. So, you can let template function argument deduction handle this for you:
template<class T, class Method, class ...Args>
static auto bounce(Method T::*func, T* priv, Args... args) -> decltype((priv->*m)(args...))
{
return (priv->*m)(args...);
}
More convenient might be to either use std::bind or a lambda to completely hide the fact that it is a member function call:
template<class Func, class ...Args>
static auto bounceCallable(Func func, Args... args) -> decltype(func(args...))
{
return func(args...);
}
And you would call it like this:
call_callback([&bar](int v){bar.baz(v);}, 11);
With a lambda, you have a syntax nicer than with std::bind, but it comes at the cost of having to repeat the signature.
I'm trying to get a way to keep the complete type of a function pointer's parameters when passed into a template function.
This is an example of what I'd like to do:
#include <stdio.h>
#include <utility>
template<typename _Ret, typename... Args>
static _Ret call(_Ret (*fp)(Args&&...), Args &&... args)
{
return fp(std::forward<Args>(args)...);
}
int foo(int arr[4])
{
printf("arr: %i,%i,%i,%i\n", arr[0], arr[1], arr[2], arr[3]);
return 0;
}
int main(int, char**)
{
int arr[4] = { 1, 2, 3, 4 };
int (*foo_ptr)(int arr[4]) = &foo;
call<int>(foo_ptr, arr);
return 0;
}
Unfortunately the type that call actually sees foo_ptr as int (*)(int*) rather than int (*)(int [4]) or int (*)(int (&)[4]).
The reason for the rvalue references is that is the only way to keep the array's type at all, but it doesn't seem to work for function pointer parameters.
As to why I want to do this, I have a nearly magical lua binding lib that is 100% template based, and requires no code to link to. In order for it to be able to support binding to properties and variables that are arrays themselves the rvalue references are required. int* and int (&)[4] are not compatible types.
The idea is to allow binding existing apis, even C apis as transparently and automagically as possible, while doing as much of the type checking at compile time as is possible.
Is this possible at all?
Edit:
Ok, my example was probably a bit too simplified. I can't actually change the definition of the functions that get passed into "call", as this library is meant to allow binding to any random function a user might want.
here for example is my static function (non method) binding method:
template<typename _Ret, typename... _Args>
LuaGlue &func(const std::string &name, _Ret (*fn)(_Args...))
{
auto new_func = new LuaGlueFunction<_Ret, _Args...>(this, name, fn);
functions.addSymbol(name.c_str(), new_func);
return *this;
}
And LuaGlueFunction happens to look like this:
template<typename _Ret, typename... _Args>
class LuaGlueFunction : public LuaGlueFunctionBase
{
public:
typedef _Ret ReturnType;
typedef _Ret (*MethodType)( _Args... );
LuaGlueFunction(LuaGlueBase *lg, const std::string &n, MethodType fn) :
g(lg), name_(n), fn_(std::forward<decltype(fn)>(fn))
{ }
~LuaGlueFunction() {}
std::string name() { return name_; }
bool glue(LuaGlueBase *luaGlue)
{
lua_pushlightuserdata(luaGlue->state(), this);
lua_pushcclosure(luaGlue->state(), &lua_call_func, 1);
//printf("add function: %s\n", name_.c_str());
lua_setglobal(luaGlue->state(), name_.c_str());
return true;
}
int invoke(lua_State *state)
{
ReturnType ret = applyTuple(g, state, fn_, args);
lua_pop(state, Arg_Count_);
stack<_Ret>::put(g, state, ret);
return 1;
}
private:
LuaGlueBase *g;
std::string name_;
MethodType fn_;
std::tuple<_Args...> args;
static const unsigned int Arg_Count_ = sizeof...(_Args);
static int lua_call_func(lua_State *state)
{
auto mimp = (LuaGlueFunction<_Ret, _Args...> *)lua_touserdata(state, lua_upvalueindex(1));
return mimp->invoke(state);
}
};
I'm attempting to allow the detection of an array, and then autobox it in a LuaGlueStaticArray type internally (that part already works, assuming I can keep the array from decaying into a pointer).
Hopefully that helps explain a little better what I'm trying to do.
There's a problem with the call function template. It needs to be defined as
template<typename _Ret, typename... Args>
static _Ret call(_Ret (*fp)(Args...), Args &&... args)
// ^^^ no &&
You want perfect forwarding for the arguments you pass in, but you do no want to force the types of the function parameters to reference types.
Next, when you pass an array to a function it decays to a pointer to the address of the first element. So your function foo is actually equivalent to
int foo(int *arr) // size information is lost
Keeping this in mind, you do not want arr to be deduced as int (&)[4] when you pass it to call, so you must pass a pointer.
call<int>(foo_ptr, &arr[0]); // pass a pointer to the beginning
After making these changes your code works. Live demo
If you want to preserve the array's size when passing it to foo, change that function to
int foo(int (&arr)[4])
{ ... }
And then call it as
decltype(foo)* foo_ptr = &foo;
call<int>(foo_ptr, arr);
As mpark points out in the comments, in both examples above there's no need to explicitly mention the return type of call, or form the function pointer foo_ptr. The calls can simply be
call(foo, &arr[0]); // with int foo(int *arr)
or
call(foo, arr); // with int foo(int (&arr)[4])
Live demo