I've been reading a tutorial by Ben Hoffman (https://benhoffman.tech/cpp/general/2018/11/13/cpp-job-system.html)
I've had a go at bashing together a version of the Job/Worker system he has, but instead of using void* for arguments then casting to a known struct, I've been trying to use variadic arguments. The idea is, a job takes in a "parent" to perform a method on, the function pointer to said method, and an Args... for the argument(s). However, I get an internal compiler error if I try to build. Here is the job class:
template <class T, typename... Args>
struct JobMemberFunc : IJob
{
JobMemberFunc(T* aParent, void (T::* f)(Args...), Args... Args)
{
parentObj = aParent;
func_ptr = f;
saved_args = ::std::make_tuple (::std::move(Args)...);
}
virtual bool invoke() override
{
if (!parentObj) { return false; }
(parentObj->*func_ptr)(::std::move(saved_args));
return true;
}
/** the object to invoke the function pointer on */
T* parentObj;
/** The function pointer to call when we invoke this function */
void (T::* func_ptr)(Args...);
::std::tuple<Args...> saved_args;
};
struct CpuJob
{
IJob* jobPtr = nullptr;
};
Then there's the AddJob method, where the internal compiler error is actually happening.
template <typename T, typename... Args>
void AddJob(T* aParent, void(T::* func_ptr)(Args...), Args... args)
{//This curly bracket is where the internal compiler error happens
CpuJob aJob = {};
JobMemberFunc<T, Args...>* jobPtr = new JobMemberFunc<T, Args...>(aParent, func_ptr,
std::forward<Args>(args)...);
aJob.jobPtr = jobPtr;
locklessReadyQueue.enqueue(aJob);
}
More than happy to be told this is a bad/wrong way of trying to do it anyway. I have thought about doing away with it and having a standardized argument list or doing something polymorphic but I really wanna make this work so I can literally ask the job system to do anything I like.
Thanks!
std::function<void()> (in combination with lambdas) already do what you're trying to do with JobMemberFunc.
void AddJob(std::function<void()>&& job)
{
locklessReadyQueue.enqueue(std::move(job));
}
With this you can submit any function call as a job.
For example, a call some_obj.some_method(some_arg) becomes:
AddJob([&] { some_obj.some_method(some_arg); });
No more ugly pointer-to-member stuff...
You can find more complete thread pooling examples here: Thread pooling in C++11
Related
Is there a way to apply the function-signature-as-template-parameter unpacking idiom in a way that works with C++/CLI managed types?
As an example, consider the following code:
#include <msclr/gcroot.h>
using namespace System;
template<typename... Args>
ref struct ManagedDelegate abstract
{
delegate void Fn(Args...);
};
template<typename Signature>
struct Method;
template<typename... Args>
struct Method<void(Args...)>
{
using Fn = typename ManagedDelegate<Args...>::Fn;
Method(Fn^ m) : m_Method(m) {}
void operator()(Args... args)
{
auto method = safe_cast<Fn^>(m_Method);
method(args...);
}
private:
msclr::gcroot<Fn^> m_Method;
};
void f1(int a, int b)
{
Console::WriteLine("a = {0}, b = {1}", a, b);
}
void f2(String^ s)
{
Console::WriteLine("s = {0}", s);
}
int main(array<String ^> ^args)
{
using Method1 = Method<void(int, int)>;
Method1 m1(gcnew Method1::Fn(&f1));
m1(4, 5);
using Method2 = Method<void(String^)>;
Method2 m2(gcnew Method2::Fn(&f2));
m2("hello world");
return 0;
}
(The separate ManagedDelegate is a little annoying, but it's not possible to declare a delegate type inside a native class, sadly.)
If you comment out all the Method2 code at the bottom, then this compiles and runs as you'd expect -- it calls f1(4, 5) and prints accordingly.
Trying to do the same thing with a managed type argument, however, causes the template to fail to match the specialisation and results in:
error C2027: use of undefined type 'Method<void (System::String ^)>'
Is this a compiler bug, or is there some way to get this to work? There are some constraints that I do need to keep to in order for this to work in my real code:
Method needs to be an unmanaged type that contains a gcroot of the delegate type.
The use of templates rather than generics is intended. I don't think any of this is possible with generics anyway.
The non-use of std::forward is also intended, since this also upsets managed types. (And I'm not intending to pass native reference arguments anyway, so it's unnecessary.)
While I prefer automatically creating the delegate type from the signature as shown here, it would also be acceptable to create the delegate outside and pass it in instead of a signature, eg:
delegate void Method1Delegate(int, int);
...
Method<Method1Delegate> m1(gcnew Method1Delegate(&f1));
But either way, I do need an Args... parameter list (both for the operator() and for other reasons). And I don't think it's possible to extract this from a managed delegate type.
I also want the operator() to keep using Args... from the Method type so that it won't accept the "wrong" parameters. (I did have an older version of the code that templated Args directly on operator(), but this gives IntelliSense the false impression that it would accept any parameters.)
If there is a way to do the above, then I'd probably want a version that works with a templated return type as well as just void. I know how to do that with the above code -- just that any rewrite shouldn't prevent that working if possible.
EDIT: as demonstration that the managed args sort of work in variadics, this can be added:
template<>
struct Method<void(String^)>
{
using Fn = typename ManagedDelegate<String^>::Fn;
Method(Fn^ m) : m_Method(m) {}
template<typename... Args>
void operator()(Args... args)
{
auto method = safe_cast<Fn^>(m_Method);
method(args...);
}
private:
msclr::gcroot<Fn^> m_Method;
};
This works, provided that the call is changed to m2(gcnew String("hello world")); to force the correct type, or operator() is changed to accept a single String^ parameter instead of an open variadic. So the problem is definitely in matching a variadic template specialisation, not elsewhere.
I can mostly do what I want by abandoning the function-signature-specialisation and just specifying the signature components separately:
template<typename R, typename... Args>
ref struct ManagedDelegate abstract
{
delegate R Fn(Args...);
};
template<typename R, typename... Args>
struct Method
{
using Fn = typename ManagedDelegate<R, Args...>::Fn;
Method(Fn^ m) : m_Method(m) {}
R operator()(Args... args)
{
auto method = safe_cast<Fn^>(m_Method);
return method(args...);
}
private:
msclr::gcroot<Fn^> m_Method;
};
//...
using Method2 = Method<void, String^>;
Method2 m2(gcnew Method2::Fn(&f2));
m2("hello world");
This is not ideal, but it does compile and work. I'm still interested in any alternative answer that does support unpacking a function signature type, however. (And I filed the original issue as a compiler bug.)
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 have a class with a function add:
class Pool {
public:
Pool() {};
template<class F, class... A>
auto add(F&& f, A&&... args) -> std::future<typename std::result_of<F(A...)>::type>
{
// return empty placeholder, for the sake of this code example
std::future<typename std::result_of<F(A...)>::type> ret;
return ret;
};
};
It should take any function with its arguments, add it to a thread pool and return a future of the result type of that function.
And a class where I use it:
class MyClass {
public:
string doIt(string) { return string("a"); };
string doIt(int, string) { return string("b"); };
void test() {
Pool myPool;
string a("test");
myPool.add(&MyClass::doIt, a); // Error
};
};
Which gives a compiler error:
Error 1 error C2914: 'Pool::add' : cannot deduce template argument as function argument is ambiguous MyClass.cpp 94
Now the problem is (I think) that the compiler can't deduce which overload I want to use. Similar to Overloaded function as argument of variadic template function.
(Also I'm not 100% clear on why I have to use "&" for class member functions, but no ampersand if I pass in a free function).
Anyway I also tried the workaround mentioned in above answer:
struct doIt_wrapper {
template <typename... T>
auto operator()(T... args) -> decltype(doIt(args...)) {
return doIt(args...);
}
};
and then modifying MyClass::test() to:
void test() {
Pool myPool;
string a("test");
myPool.add(doIt_wrapper(), a);
};
But it also gives me a compiler error:
error C2893: Failed to specialize function template 'unknown-type doIt_wrapper::operator ()(T...)' C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xrefwrap 58
I also tried a few variants like myPool.add(doIt_wrapper<string>() and with/without '&' but they all generate one or the other compiler error.
I think I don't fully understand the problem yet and I would be glad if someone could shed light on it. Also I am looking for a proper solution to this problem. It can't really be the case that this only works as long as there are no two functions with the same name, and as soon as there are, everything breaks down without a proper, generic solution?
Edit: Fixed a few typos and uploaded a minimal example here: http://ideone.com/eX1r1l
As others have mentioned, the problem is that doIt() is not callable inside the doIt_wrapper class as it also needs a pointer to the object called on.
You could just modify the doIt_wrapper operator() to also take a pointer to the object and pass a pointer to this as first argument to add().
It would then look something like this:
#include <iostream>
#include <future>
using namespace std;
class Pool {
public:
Pool() {};
template<class F, class... A>
auto add(F&& f, A&&... args) -> std::future<typename std::result_of<F&&(A&&...)>::type>
{
// return empty placeholder, for the sake of this code example
std::future<typename std::result_of<F&&(A&&...)>::type> ret;
return ret;
};
};
class MyClass {
public:
string doIt(string) { return string("a"); };
string doIt(int, string) { return string("b"); };
struct doIt_wrapper
{
template<class T, class... Ts>
auto operator()(T&& t, Ts&&... args) -> decltype(t->doIt(std::forward<Ts>(args)...))
{
return t->doIt(std::forward<Ts>(args)...);
}
};
void test() {
Pool myPool;
string a("test");
myPool.add(doIt_wrapper(), this, a); // No error no more
};
};
int main() {
// your code goes here
MyClass my;
my.test();
return 0;
}
This way you don't have to do the casts. The code compiles on both GCC and Clang.
You may use lambda:
myPool.add([this](const std::string& s) {doIt(s);}, a);
or even
myPool.add([this, a]() {doIt(a);});
Currently, you may indicate which overload to use that way:
myPool.add(static_cast<std::string (MyClass::*) (std::string)>(&MyClass::doIt), a);
Note that doIt is a method (not a free function or static function), so you have to call it with an object.
If you add static to doIt, you may choose the overload with
myPool.add(static_cast<std::string (*) (std::string)>(&MyClass::doIt), a);
The problem is that non-static member functions have a hidden, implicit this parameter that points to the instance that called it. Your compiler is right to reject it as it doesn't have the correct arguments for the function. Sending in this as an additional bound parameter will work:
myPool.add(&MyClass::doIt, this, a);
// ^^^^
Using a lamda expression will work as well.
Also, the standard library function std::async() already does what you're trying to do here, and more. Consider using that instead.
Edit: You also need to cast to the correct type to select the correct overload. #Jarod42 already shows you how.
I'm trying hard for some hours and didn't manage to get this working.
I have a templated class spinlock:
template<typename T> class spinlock {
// ...
volatile T *shared_memory;
};
I'm trying to create something like this:
// inside spinlock class
template<typename F, typename... Ars>
std::result_of(F(Args...))
exec(F fun, Args&&... args) {
// locks the memory and then executes fun(args...)
};
But I'm trying to use a polymorphic function so that I can do this:
spinlock<int> spin;
int a = spin.exec([]() {
return 10;
});
int b = spin.exec([](int x) {
return x;
}, 10); // argument here, passed as x
// If the signature matches the given arguments to exec() plus
// the shared variable, call it
int c = spin.exec([](volatile int &shared) {
return shared;
}); // no extra arguments, shared becomes the
// variable inside the spinlock class, I need to make
// a function call that matches this as well
// Same thing, matching the signature
int d = spin.exec([](volatile int &shared, int x) {
return shared + x;
}, 10); // extra argument, passed as x... should match too
// Here, there would be an error
int d = spin.exec([](volatile int &shared, int x) {
return shared + x;
}); // since no extra argument was given
Basically, I'm trying to make an exec function that accepts F(Args...) or F(volatile T &, Args...) as an argument.
But I can't manage to make automatic detection of types.
How could I accomplish that?
Firstly, this signature will not compile:
// inside spinlock class
template<typename F, typename... Ars>
std::result_of(F(Args...))
exec(F fun, Args&&... args) {
// locks the memory and then executes fun(args...)
};
The return type needs to be
typename std::result_of<F(Args...)>::type
If your compiler implements N3436 then this function will not participate in overload resolution when fun(args...) is not a valid expression, but that is not required in C++11 and not implemented by many compilers yet. You will need to implement your own SFINAE check to prevent result_of giving an error when fun(args...) is not valid, or rewrite it without result_of
template<typename F, typename... Args>
auto
exec(F fun, Args&&... args) -> decltype(fun(std::forward<Args>(args)...))
{
// locks the memory and then executes fun(args...)
}
Then you can overload it for functions that need the additional parameter passed in:
template<typename F, typename... Args>
auto
exec(F fun, Args&&... args) -> decltype(fun(*this->shared_memory, std::forward<Args>(args)...))
{
// locks the memory and then executes fun(*shared_memory, args...)
}
When fun(std::forward<Args>(args)...) is not valid the first overload will not participate in overload resolution. When fun(*this->shared_memory, std::forward<Args>(args)...) is not valid the second overload will not participate in overload resolution. If neither is valid the call will be ill-formed, if both are valid the call will be ambiguous.