I can't figure out how to pass member function with variadic template arguments to std::thread constructor. I have a method that receives function and its arguments and need to pass them to other method which is invoked in new thread and calls passed function there.
Here is simplified version:
class Test
{
public:
template<typename Function, typename... Args>
void Run(Function&& f, Args&&... args)
{
std::thread t(&Test::Operation, this, f, args...); // how???
t.detach();
}
template<typename Function, typename... Args>
void Operation(Function&& f, Args&&... args)
{
f(args...);
}
};
Test test;
test.Run([](const std::string& msg) { std::cout << msg; }, "Hi!");
There is something wrong in passing arguments this way, I get the following error: 'std::thread::thread': no overloaded function takes 4 arguments. How can I do this?
The problem here is that when you pass &Test::Operation to the thread constructor, it can't deduce the template parameters for &Test::Operation. (If you want to understand why this deduction cannot be done, you should probably ask a separate question.) The point is that you need to explicitly specify the template arguments for &Test::Operation.
This will look like this:
template<typename Function, typename... Args>
void Run(Function&& f, Args&&... args)
{
std::thread t(&Test::Operation<std::decay_t<Function>, std::decay_t<Args>...>,
this, std::forward<Function>(f), std::forward<Args>(args)...);
t.detach();
}
I added perfect forwarding for you: it's important because you don't want to perform an unnecessary copy, right?
But why do we need the decay_t? It's because the thread constructor decays its arguments before storing copies of them in the new thread's internal storage, so, for example, if you pass in "Hi!", then the deduced type is const char (&)[4], but it will become a const char* once decayed, and the decay is irreversible, so Test::Operation must not be expecting a const char (&)[4], which cannot be initialized from the decayed const char*. So Test::Operation must be specified to take the decayed type.
You also probably want perfect forwarding during the actual invocation.
Link: http://coliru.stacked-crooked.com/a/c9d04c03a3758b51
Related
I am working in C++11 and have the following code that compiles. But the problem is that the function func in the below example can also be called with a std::function, lambda, pointer to a function etc.
Instead, I want that func should only be called by a pointer to a non-static member function of any class. That is, I want to restrict this function only member function pointers.
template <typename Callable, typename... Args> void func(Callable&& callable, Args&&... args)
{
}
struct Test
{
int someMember(int x)
{
return x;
}
};
void g(int, int, int)
{
}
int main()
{
func(g, 1, 1, 1); //this works currently but it should be rejected in the modified program
func([](int){}, 42); //this works currently but it should be rejected in the modified program
Test test;
func(&Test::someMember, test, 1);// this works currently and should work in the modified version
}
As we can see in the above program, all of the calls to func works. But I want that only the call func(&Test::someMember, test, 1); should work and the other two calls should be rejected.
So how can I achieve this. Maybe there is a way to use SFINAE or some other metaprogramming technique.
I think static_assert (with std::is_member_function_pointer) is the perfect tool for the situation. No need to change the signature of func, and the error message can be whatever you want, so it's clearer than, for example, a substitution failure.
To call callable, you may use std::mem_fn.
template <typename Callable, typename... Args>
void func(Callable callable, Args&&... args)
{
static_assert(std::is_member_function_pointer<Callable>::value, "callable must be a member function");
std::mem_fn(callable)(args...);
}
Demo
This can be done by setting up the template parameters in such a way that only pointers to member function are accepted(as shown below). In particular, we can have 4 template parameters corresponding to the class, member function parameters, object of that class and finally the arguments passed to that member function.
template<typename className, typename... Param,typename Ret, typename... Args>
void func(Ret (className::*ptrFunc)(Param... param),className& Object, Args... args)
{
(Object.*ptrFunc)(args...); //std::invoke(ptrFunc, Object, args...) in C++17
}
int main()
{
Test test;
func(&Test::someMember, test, 1);//only this form works now
}
Working demo
Maybe there is a way to use SFINAE or some other metaprogramming technique.
That would do it, since we have std::is_member_function_pointer.
template <typename Callable, typename... Args>
typename std::enable_if<std::is_member_function_pointer<Callable>::value, void>::type
func(Callable callable, Args&&... args)
{
}
If the predicate is false, enable_if produces no type, and our template has no return type, making the function non-viable.
The change to pass by value is because it makes to controlling condition simpler, and because we are only passing pointers to members (fairly cheap to copy).
Need to create variadic template<T> function with different arg types that will call constructor of T with given arguments, sort of like when creating a thread but reverse (when creating a thread, its constructor calls function at given funct pointer).
So in pseudo code it should look something like this
template<typename T>
T* CreateNew( ARGS ) {
return new T( ARGS ); //Constructor Gets Same Arguments That Were
} //Passed To The Function
Want this to behave like when creating threads, when they call functions with their arguments that are of different types (which I am unsure how to achive).
Its not entirely clear to me but I think you want to look up variadic templates, e.g.:
template <typename T, typename... Args>
T* CreateNew(Args... args) {
return new T(args...);
}
Adding Example:
#include <iostream>
class A {
public:
A(int a){
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
A(std::string a){
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
A(int a,std::string b){
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
};
template<typename T, typename... Args>
T* create(Args... args){
return new T(args...);
}
int main(){
A b(1);
A c("a");
A d(1,"a");
A* bp = create<A>(1);
A* cp = create<A>("a");
A* dp = create<A>(1,"a");
// This code leaks
return 0;
}
Note that because the changes are kept as minimal as possible, we still return a T* here as the original code. Most of the time, this is not a good idea since ownership is passed via raw pointers. Therefore, as suggested by the comments, you might want to use a std::unique_ptr, which would make your CreateNew function basically equivalent to std::make_unique.
The correct way to write this function is
template <typename T, typename... Args>
T* CreateNew(Args&&... args) {
return new T(std::forward<Args>(args)...);
}
Without the forwarding reference Args&& and without std::forward, the original value categories of the passed arguments will not be propagated to T's constructor, causing potential performance and semantic problems.
I'd like to create template function that would create object basing on template typename and parameters pack.
I created a function that is supposed to create object based on typename from template, and I would also like to pass parameters pack to that template i order to pass parameters to constructor. Is this correct?:
template<typename TComponent, typename... Args>
void CreateComponent(Args... args)
{
std::shared_ptr<TComponent> component = std::make_shared<TComponent>(args ...);
}
I also wanted to pass those parameters to another fucntion like this:
template<typename TComponent, typename... Args>
void AddComponent(Args... args)
{
m_world->AddComponent<TComponent, Args>(m_id, args...);
}
But compiler returns an error " 'args' parameter pack must be expanded in this context"
Is it even possible to achieve what I want to achieve ?
But compiler returns an error " 'args' parameter pack must be expanded in this context"
Yes: you've forgotten to expand the types
m_world->AddComponent<TComponent, Args...>(m_id, args...);
// ...................................^^^
As pointed by Jarod42, according to the circumstances, you could avoid to explicit the Args... expansion
m_world->AddComponent<TComponent>(m_id, args...);
// no more Args...
and let the compiler deduce the types through args... (but we should see the AddComponent() definition).
Anyway, I don't see errors in your CreateComponents() function but, as correctly says François Andrieux in a comment, you don't using perfect forwarding.
It's a too-great argument to explain in an answer but, this way, you're renouncing to move semantics advantages (that is: you, potentially, make some unnecessary copies).
The following is your CreateComponents() function enabling perfect forwarding
template <typename TComponent, typename ... Args>
void CreateComponent (Args && ... args)
{ // .....................^^ forwarding reference added
std::shared_ptr<TComponent> component
= std::make_shared<TComponent>(std::forward<Args>(args)...);
} // ..............................^^^^^^^^^^^^^^^^^^^^^^^^
Say I have a function foo() with takes advantage of c++ variadic templates feature. Now, what's the difference between these implementations:
template <typename... Args>
void foo(Args... args) {
whatever(args...);
}
template<typename... Args>
void foo(Args&... args) {
whatever(args...);
}
template<typename... Args>
void foo(Args... args) {
whatever(&args...);
}
template<typename... Args>
void foo(Args&&... args) {
whatever(std::forward<Args>(args)...);
}
template <typename... Args>
void foo(Args... args) {
whatever(args...);
}
foo gets copies of args and passes them to whatever as l-values.
template<typename... Args>
void foo(Args&... args) {
whatever(args...);
}
foo gets l-value references to args and passes them to whatever as l-values.
template<typename... Args>
void foo(Args... args) {
whatever(&args...);
}
foo gets copies of args and passes them to whatever as pointers to l-values. Be careful of object lifetimes here.
template<typename... Args>
void foo(Args&&... args) {
whatever(std::forward<Args>(args)...);
}
foo gets forwarding references to args. Whether they are l-values or r-values depends on what happens at the call site. They are then perfect-forwarded to whatever, preserving their reference type. Scott Meyers originally called these "universal" references, but forwarding reference is the preferred terminology now.
The first one takes its arguments by value. The second one takes its arguments by lvalue reference (so non-const rvalues cannot be used). The third one also takes its arguments by value, but passes pointers to whatever. The fourth one takes its arguments by forwarding reference and perfect-forwards them to whatever.
There is nothing magical about the variadic templates; the rules are the same as if there were only one argument.
I'd want to implement a function caller that works just like the thread constructor. For example
std::thread second (bar,0);
will start a thread which calls bar with the single argument 0. I would like to do the same thing, but I do not know how.
For example, given:
void myFunc(int a){
cout << a << endl;
}
I would like:
int main() {
caller(myFunc,12);
}
to call myFunc with the parameter 12.
std::bind will make a callable object from any callable object with an arbitrary set of parameters, just as the thread constructor does. So just wrap that in a function that calls it:
template <typename... Args>
auto caller(Args &&... args) {
return std::bind(std::forward<Args>(args)...)();
}
Note that the auto return type requires C++14 or later. For C++11, you'll have to either return void, or specify the type:
auto caller(Args &&... args)
-> decltype(std::bind(std::forward<Args>(args)...)())
If all you want to do is call an arbitrary function with an arbitrary argument, that's just a template on both types:
template <typename Function, typename Arg>
void call_with_one(Function&& f, Arg&& arg) {
f(std::forward<Arg>(arg));
}
which you can expand to call with any number of args by making it variadic:
template <typename Function, typename... Arg>
void call_with_any(Function f, Arg&&... args) {
f(std::forward<Arg>(args)...);
}
Or really f should be a forwarding reference as well:
template <typename Function, typename... Arg>
void call_with_any(Function&& f, Arg&&... args) {
std::forward<Function>(f)(std::forward<Arg>(args)...);
}
Note that this will only work with functions and objects that implement operator(). If f is a pointer-to-member, this will fail - you will have to instead use std::bind as Mike Seymour suggests.