Given the following callable object:
struct callable : public std::unary_function <void, void>
{
void
operator()() const
{
std::cout << "hello world" << std::endl;
}
};
a std::tr1::reference_wrapper<> calls through it:
callable obj;
std::tr1::ref(obj)();
Instead, when the operator() accepts an argument:
struct callable : public std::unary_function <int, void>
{
void
operator()(int n) const
{
std::cout << n << std::endl;
}
};
std::tr1::bind accepts a reference_wrapper to it as a callable wrapper...
callable obj;
std::tr1::bind( std::tr1::ref(obj), 42 )();
but what's wrong with this?
std::tr1::ref(obj)(42);
g++-4.4 fails to compile with the following error:
test.cpp:17: error: no match for call to ‘(std::tr1::reference_wrapper<const callable>) (int)’
/usr/include/c++/4.4/tr1_impl/functional:462: note: candidates are: typename std::tr1::result_of<typename std::tr1::_Function_to_function_pointer<_Tp, std::tr1::is_function::value>::type(_Args ...)>::type std::tr1::reference_wrapper<_Tp>::operator()(_Args& ...) const [with _Args = int, _Tp = const callable]
The implementation of tr1 reference_wrapper of g++-4.4 is equipped with the following operator:
template<typename... _Args>
typename result_of<_M_func_type(_Args...)>::type
operator()(_Args&... __args) const
{
return __invoke(get(), __args...);
}
It takes arguments by reference. Hence the reference_wrapper cannot be invoked passing an r-value argument:
std::tr1::ref(obj)(42);
instead:
int arg = 42;
std::tr1::ref(obj)(arg);
works just fine.
std::tr1::bind( std::tr1::ref(obj), 42 )()
works because bind takes the arguments by copy.
What makes you sure there's anything wrong with it? I believe this should work:
#include <functional>
#include <iostream>
struct callable : public std::unary_function <int, void>
{
void
operator()(int n) const
{
std::cout << n << std::endl;
}
};
int main() {
callable obj;
std::tr1::ref(obj)(42);
return 0;
}
At least with MS VC++ 9, it compiles and executes just fine, and offhand I can't see any reason it shouldn't work with other compilers as well.
Edit: Doing some looking at TR1, I take that back. It works with VC++ 9, but I don't think it's really required to work. VC++ 9 doesn't support variable template arguments, so they're supporting this via overloading. Rather deeply buried (<functional> includes <xawrap>, which includes <xawrap0> [which, in turn, includes <xawrap1>]) is code to generate reference and (importantly) reference to const variants for up to 10 arguments. It's almost certainly the inclusion of the reference to const variants that allows this to work.
First of all, the use of std::unary_function for a null-ary function looks odd. "unary" = takes one argument. I'm not sure whether it's okay to use ArgType=void.
Secondly, you have it backwards. The first template parameter is about the argument type and the second one is about the return type. So, your unary function object should be defined like this:
struct callable : public std::unary_function<int,void>
{
void operator()(int n) const
{
std::cout << n << std::endl;
}
};
Related
Thing simple enough, I want to forward the call of a member function, along with its arguments, as described in the following snippet.
Please note that this is not a duplicate of this question, nor this one.
#include <iostream>
#include <functional>
template<class Function, class ... Args>
auto forward_args(Function&& f, Args&& ... args)
{
return f(std::forward<Args>(args)...);
}
int f(int i) { return i; }
struct A {
int get(int i) const { return i; }
};
int main()
{
std::cout << forward_args(f, 2) << std::endl; //ok
A a;
//std::cout << forward_args(&A::get, a, 2) << std::endl; //ko
static auto wrong_wrapper = &A::get;
//std::cout << forward_args(wrong_wrapper, a, 2) << std::endl; //ko again
static std::function<int (const A&, int)> wrapper = &A::get;
std::cout << forward_args(wrapper, a, 2) << std::endl;
}
The commented lines in the main function don't compile (g++ 10.2.0 -- error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘f (...)’, e.g. ‘(... ->* f) (...)’)
I don't quite understand what the compiler is trying to tell me, considering the last cll with the std::function wrapper does work. And, beside fixing the code, I'd also like to know why it doesn't work.
Calling a member function through pointer-to-member still requires this pointer, as in usual (direct) invocations. Simply put, you could succeeded calling A::get() like
static auto wrong_wrapper = &A::get;
(a.*wrong_wrapper)(2);
but what you got after forward_args was instantiated is
A::get(a, 2);
which is not the correct syntax in its nature.
Solution
As it has been already said in the comments section, if you are allowed to use C++17, employ std::invoke. If you aren't, you can work it around using std::reference_wrapper, which accepts any callable type.
template<class Function, class ... Args>
auto forward_args(Function f, Args&& ... args)
{
return std::ref(f)(std::forward<Args>(args)...);
}
I don't forward f here because std::reference_wrapper requires that the object passed is not an rval.
UPD:
Don't forget to specify the trailing return type of forward_args if you use C++11
template<class Function, class ... Args>
auto forward_args(Function f, Args&& ... args) -> decltype(std::ref(f)(std::forward<Args>(args)...))
{
return std::ref(f)(std::forward<Args>(args)...);
}
std::function works because it uses std::invoke which handles calling pointer to member function.
As the solution you could write:
template<class Function, class ... Args>
auto forward_args(Function&& f, Args&& ... args) {
return std::invoke(std::forward<Function>(f), std::forward<Args>(args)...);
}
Syntax for calling member function for an object are:
obj.memberFunction();
obj->memberFunction();
or if you have a pointer to member function:
using Ptr = int (A::*)(int) const;
Ptr p = &A::get;
A a;
(a.*p)(1); // [1]
(obj.*memberFuncPtr)(args...);
the line [1] is valid syntax for calling member function pointed by a pointer. In your case you try A::get(a,2) which is just not valid and cannot work.
Alright, first thing, I still don't understand why forward_args(&A::get, a, 2) doesn't work. Part of the answer was "you need this", but I actually provide it with the second parameter, right ? How is that different from the std::function wrapper ?
On the other hand, while the workarounds proposed in above answer work on the snippet, I actually simplified my original problem too much. I actually need to launch tasks asynchronously, in the following code
thread safety has been removed
yeah, I want to pack all calls in a single data structure, namely tasks, which is wy I start building up wrappers
I don't understand how I can use the proposed solutions to the code below.
#include <iostream>
#include <future>
#include <functional>
#include <queue>
std::queue<std::function<void()>> tasks;
template<class Function, class ... Args>
auto enqueue(Function&& f, Args&& ... args) -> std::future<decltype(f(args...))>
{
std::function<decltype(f(args...))()> func = std::bind(std::forward<Function>(f), std::forward<Args>(args)...);
auto task_ptr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(func);
std::function<void()> wrapper = [task_ptr]() //wrapper to match types of 'tasks'... ugly
{
(*task_ptr)();
};
tasks.push(wrapper);
return task_ptr->get_future();
}
void indep() {}
struct A {
int get(int i) const { return i; }
};
int main()
{
enqueue(indep);
A a;
//enqueue(&A::get, a, 2); //wrong
static auto wrapper_wrong = &A::get;
//enqueue(wrapper_wrong, a, 2); //wrong again
static std::function<int(const A&,int)> wrapper = &A::get;
enqueue(wrapper, a, 2); //ok
static auto autoptr = std::mem_fn(&A::get);
enqueue(autoptr, a, 2); //ok again
}
Suppose you have the following pair of functions:
void f(const int&) {
// Do something, making a copy of the argument.
}
void f(int&&) {
// Do the same thing, but moving the argument.
}
They are fairly redundant—the only difference between the functions being whether they copy or move their argument. Of course, we can do better by re-writing this as a single template function:
template<typename T>
void g(T&&) {
// Do something, possibly using std::forward to copy or move the argument.
}
This works, and is a commonly used idiom in practice. But the template might be instantiated into three functions, up from our two above. We can verify this occurs with the following piece of code:
#include <iostream>
template<typename T> constexpr char *type = nullptr;
template<> constexpr const char *type<int&> = "int&";
template<> constexpr const char *type<const int&> = "const int&";
template<> constexpr const char *type<int> = "int";
template<typename T>
void g(T&&) {
std::cout << reinterpret_cast<void*>(&g<T>)
<< " = &g<" << type<T> << ">" << std::endl;
}
int main() {
int i = 0;
const int& cr = 0;
g(i);
g(cr);
g(0);
return 0;
}
/*
Prints:
0x100f45080 = &g<int&>
0x100f45100 = &g<const int&>
0x100f45180 = &g<int>
*/
This has added a third function for the case when T = int&, which we didn't have when we were using our non-templated function f above. In this case, we don't actually need this non-const l-value reference version of the function—given f was sufficient for our original needs—and this increases the size of our code, especially if we have many template functions written this way that call each other.
Is there a way to write our function g above so that the compiler will automatically deduce T = const int& when g(i) is called in our example code? I.e., a way where we don't have to manually write g<const int&>(i) yet still get the desired behavior.
It is a subjective point-of-view to say "forward references" ("universal references") are better than dedicated overloads. There are certainly many cases where this is true, but if you want to have full control they won't do all the jobs.
You could explicitly make sure users do not pass non-const lvalue references, by adding
static_assert(!std::is_lvalue_reference<T>::value || std::is_const<typename std::remove_reference<T>::type>::value, "only call g with const argument");
inside g, but this is not in all cases a very good solution.
Or you do what is done for vector::push_back(...) and provide explicit overloads -- but this was your starting point, see https://en.cppreference.com/w/cpp/container/vector/push_back.
The 'correct' answer just depends on your requirements.
Edit:
the suggestion of #Sjoerd would look something like:
template <typename T>
class aBitComplicated {
public:
void func(T&& v) { internal_func(std::forward<T>(v)); }
void func(const T& v) { internal_func(v); }
private:
template <typename U>
void internal_func(U&& v) { /* your universal code*/ }
};
There also a bit more sophisticated/complicated version of this, but this here should be the most simple version to achieve what you asked for.
I'm trying to write a generic obj factory using variadic template to call constructors of various classes. code as follow:
#include <iostream>
#include <string>
#include <memory>
#include <functional>
#include <unordered_map>
template<typename T>
class ObjFactory {
public:
typedef std::shared_ptr<T> ObjPtr;
typedef std::function<ObjPtr(void)> CreatorFunc;
public:
void registerCreator(const std::string &name, const CreatorFunc &creator)
{ m_dictCreator[name] = creator; }
ObjPtr getObj(const std::string &name) const
{
auto it = m_dictCreator.find(name);
return (it == m_dictCreator.end() ? nullptr : (it->second)());
}
private:
std::unordered_map<std::string, CreatorFunc> m_dictCreator;
};
using namespace std;
struct Base {
virtual ~Base() {}
virtual void greet() const
{ cout << "I am Base" << endl; }
};
struct Derived : Base {
Derived() : x(0), y(0) {}
Derived(int a, int b) : x(a), y(b) {}
int x, y;
virtual void greet() const
{ cout << "I am Derived x = " << x << " y = " << y << endl; }
};
template<typename T, typename... Args>
std::shared_ptr<T> create_obj(Args... args) // This OK
// std::shared_ptr<T> create_obj(Args&&... args) // WRONG
{ return std::make_shared<T>(std::forward<Args>(args)...); }
int main()
{
ObjFactory<Base> factory;
factory.registerCreator("default", create_obj<Derived>);
factory.registerCreator("withArgs", std::bind(create_obj<Derived, int, int>, 1, 2));
do {
auto pObj = factory.getObj("default1");
if (pObj) { pObj->greet(); }
} while (0);
do {
auto pObj = factory.getObj("withArgs");
if (pObj) { pObj->greet(); }
} while (0);
return 0;
}
In most examples, variadic arg always write like this "Args&&..." in function arg list. but this does not work with bind, compile error msg like this (clang-902.0.39.2)
error: no viable conversion from '__bind
(&)(int &&, int
&&), int, int>' to 'const ObjFactory::CreatorFunc' (aka 'const function ()>')
factory.registerCreator("withArgs", std::bind(create_obj, 1, 2));
After removing the "&&", it works OK
But I don't know why?
Universal references only work in a deduced context. They do not function as you expect when the template parameters are explicitly specified.
Given the function template
template <typename... Args>
void foo(Args&&... args) {}
And the call
int a = 1;
int b = 2;
foo(a, b);
Args will be deduced to be {int&, int&}. Reference collapsing is applied, and int& && gets collapsed to just int&. That means the types of the values in args are {int&, int&}.
If you call it with rvalues for arguments (i.e. foo(1, 2)) then Args will be deduced to be {int, int} and the types of the values in args become {int&&, int&&}.
That's the basics of universal references, so now let's look at what happens when you call
auto fn = std::bind(foo<int, int>, 1, 2);
fn();
Here, you've not allowed template argument deduction to take place so Args is {int, int} and foo is therefore expecting arguments of type {int&&, int&&}. The values 1, and 2 are copied into the bind object and passed to the callable as lvalues though. Rvalue references can't bind to lvalues, and so the call fails to compile.
The way to make this work correctly is to use a lambda instead of std::bind:
auto fn = []() { foo(1, 2); };
fn();
With a lambda, template argument deduction works as normal, and 1, and 2 remain rvalues. Everything works as expected and the universal references do their job because they're being used in a deduced context.
when using forwarding references you need to let argument being deduced otherwise you can't perfect forward them because you won't know the real type to use for them.
in your case you gave a type create_obj<Derived, int, int>
the function will be instantiated to std::shared_ptr<Derived> create_obj(int&&, int&&) and have no flexibility it will just be taking r-value int.
and you assigned the callable to a const CreatorFunc& and so the closure was const and your callable couldn't receive const arguments
replacing create_obj<Derived, int, int> by create_obj<Derived, const int&, const int&> which cause create_obj to be instantiated as std::shared_ptr<Derived> create_obj(const int&, const int&) will work in this case but would still not have the flexibility of forwarding references.
the real solution is to use lambda.
The following template definition
template <typename Func, typename ReturnType, typename... Arguments>
class Command
{
public:
Command(Func f) : m_func(f) { }
ReturnType operator()(Arguments... funcArgs) { return m_func(funcArgs...); }
private:
Func m_func;
};
gives an error message with gcc 4.7.3 (error: field 'Command::m_func' invalidly declared function type) when instantiated with the following test code:
void testFunction(int i, double d)
{
std::cout << "TestFunctor::operator()(" << i << ", " << d << ") called." << std::endl;
}
int main()
{
void (&fRef)(int, double) = TestFunction;
Command<void(int, double), void, int, double> testCommand(fRef);
}
The error message also occurs if I pass TestFunction without the address-of operator into the testCommand constructor, but disappears if I pass either an explicitly named function pointer or use the address-of operator to pass the parameter. I'm under the impression that this code should work given Chapter 5 of Modern C++ Design.
What is the reasoning behind not being able to store a reference to a function, but function pointers work fine? Are there any workarounds that would allow this to compile without losing support for being able to pass functors as arguments to Command's constructor as well?
Changing one line could fix it:
Command<void(*)(int, double), void, int, double> testCommand(fRef);
The difference is, you're passing a function pointer now, instead of a function type. (Functions aren't copyable, but pointers are).
The reference fRef decays to a function pointer when you pass it.
I wouldn't suggest using std::function if performance mattered.
See it live on Coliru
Note that with a little rewriting, you can make it all work much nicer:
int main()
{
auto command = make_command(testFunction);
command(1, 3.14);
}
To do this, I'd suggest changing the Command template to be:
template <typename Func>
class Command
{
Func m_func;
public:
Command(Func f) : m_func(f) { }
template <typename... A> auto operator()(A... args) const
-> decltype(m_func(args...))
{ return m_func(args...); }
};
And now you can have type-deduction on the Func template parameter by having a factory function:
template <typename Func> Command<Func> make_command(Func f)
{
return Command<Func>(f);
}
See this approach live on Coliru too. Of course, the output it the same:
TestFunctor::operator()(1, 3.14) called.
C++11 offers an std::function template. You don't have to mess with function pointers.
You can pass those by reference, copy them, move them and they can even be used to store lambdas:
std::function<void()> func = []() { std::cout << "Hi" << std::endl; };
I have a callback implementation using rvalue references to store arguments that works fine with gcc, but fails to compile in VS 2010 on some code. A short version:
#include <iostream>
#include <string>
class B {
public:
virtual void execute() = 0;
};
template<typename FuncType, typename ArgType>
class F : public B {
public:
F(FuncType func, ArgType && arg) : f(func), arg(arg) {}
void execute() { f(arg); }
private:
FuncType f;
ArgType && arg;
};
template<typename FuncType, typename ArgType>
B * registerFunc(FuncType func, ArgType && arg)
{
return new F<FuncType, ArgType>(func, arg);
}
void myFunction(std::string text)
{
std::cout << "Function " << text << " here" << std::endl;
}
int main()
{
const char text1[] = "sample1";
std::string text2("sample2");
B * b = registerFunc(myFunction, text1);
b->execute();
delete b;
b = registerFunc(myFunction, text2);
b->execute();
delete b;
// VS 2010 fails because of this call
b = registerFunc(myFunction, text2.c_str());
b->execute();
delete b;
return 0;
}
With gcc 4.4 this produces:
$ g++ clbck.cpp -std=c++0x -o clbck && ./clbck
Function sample1 here
Function sample2 here
Function sample2 here
However it fails to compile in VS 2010 when trying to instantiate registerFunc because of the marked line:
error C2664: 'F::F(FuncType,ArgType &&)' : cannot convert parameter 2 from 'const char *' to 'const char *&&'
with
[
FuncType=void (__cdecl *)(std::string),
ArgType=const char *
]
You cannot bind an lvalue to an rvalue reference
Googling discovered a similar error with Boost 1.44 on VS2010, but the recommended solution there is not to use rvalue references at all. Is there really no other way?
And while you're at it, is there something wrong with the way I'm handling these callbacks? It works fine with function pointers and functors (I have yet to test lambdas), the only downside I found is the one described above. (Bear in mind the code shown here is just a small demonstration, in the actual code I don't give user any pointers; I'm actually using this to execute functions in different threads in a Qt application).
I believe that Visual Studio is right to complain, and you can find an explanation here.
In registerFunc, the expression arg is an lvalue (it has a name). If you want to forward it as an rvalue reference, you have to use std::forward :
template<typename FuncType, typename ArgType>
B * registerFunc(FuncType func, ArgType && arg)
{
return new F<FuncType, ArgType>(func, std::forward<ArgType>(arg));
}
The same issue occurs in FuncType constructor, but adding an std::forward there yields an interesting warning :
reference member is initialized to a temporary that doesn't persist after the constructor exits
Unfortunately, I don't enough of rvalue references to help you further, but I doubt that an rvalue reference member makes any sense : rvalue references bind to objects that are about to die, would it make any sense to store that ?
It's not exactly clear what you hope to achieve with respect to the rvalue reference member. It just doesn't look right. You should avoid storing a reference. You can still use things like std::ref and std::cref if you want the function object to store a reference-like object (much like std::bind behaves).
The issue you ran into is that it's not allowed to initialize an rvalue reference with an lvalue of the target type. But you try to do this because the constructor's parameter "arg" is a named rvalue reference which makes it an lvalue expression in the initializer list. You probably used an old GCC version to compile this code. Newer versions will also complain about this.
You can save yourself some trouble by relying on std::bind:
template<class FuncType>
class F : public B {
public:
explicit F(FuncType func)
: f(std::forward<FuncType>(func))
{}
void execute() { f(); }
private:
FuncType f;
};
....
auto fun = std::bind(myFunction,text2.c_str());
B* ptr = new F<decltype(fun)>(fun);
If you really want to deal with the parameter binding yourself, you should do it like this:
template<class FuncType, class ParamType>
class F : public B {
public:
F(FuncType func, ParamType para)
: f(std::forward<FuncType>(func))
, p(std::forward<ParamType>(para))
void execute() { f(p); }
private:
FuncType f;
ParamType p;
};
Keep in mind that the parameter type T&& where T can be deduced has a special meaning. It's a "catch-all" parameter. Template argument deduction will make T an lvalue reference (and T&& as well by the reference collapsing rules) in case the argument was an lvalue. So, if you always want the parameter to be stored as a copy you have to write
template<class FuncType, class ArgType>
B * registerFunc(FuncType func, ArgType && arg)
{
typedef typename std::decay<ArgType>::type datype;
return new F<FuncType,datype>(func, std::forward<ArgType>(arg));
}
I would prefer a registerFunc function like this. It copies the function object and parameter object by default. Overriding this can be done via std::ref and std::cref:
registerFunc(some_func,std::cref(some_obj));
Why not just use lambda expressions?
class B {
virtual void execute() = 0;
};
template<typename T> class F : public B {
T t;
public:
F(T&& arg) : t(std::forward<T>(arg)) {}
void execute() { return t(); }
};
template<typename T> F<T> make_f(T&& t) {
return F<T>(std::forward<T>(t));
}
int main() {
std::string var;
B* callback = make_f([=]() {
std::cout << var << std::endl;
});
}
Or, indeed, std::function<void()>, which is what it's for.