How can I bind a member function to a std::function? - c++

I want to do an array of OIS::Keys (int) and of std::function.
I have this :
struct UserCommands
{
OIS::KeyCode key;
std::function<bool(Worms *, const Ogre::FrameEvent& evt)> func;
};
UserInput input;
UserCommands usrCommands[] =
{
{
OIS::KC_A, std::bind(&input, &UserInput::selectBazooka)
},
};
But when I try to compile this I have this compile error :
In file included from includes/WormsApp.hh:5:0,
/src/main.cpp:2:
/includes/InputListener.hh:26:25: error: could not convert ‘std::bind(_Func&&, _BoundArgs&& ...) [with _Func = UserInput*; _BoundArgs = {bool (UserInput::*)(Worms*, const Ogre::FrameEvent&)}; typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type = std::_Bind<UserInput*(bool (UserInput::*)(Worms*, const Ogre::FrameEvent&))>](&UserInput::selectBazooka)’ from ‘std::_Bind_helper<false, UserInput*, bool (UserInput::*)(Worms*, const Ogre::FrameEvent&)>::type {aka std::_Bind<UserInput*(bool (UserInput::*)(Worms*, const Ogre::FrameEvent&))>}’ to ‘std::function<bool(Worms*, const Ogre::FrameEvent&)>’
OIS::KC_A, std::bind(&input, &UserInput::selectBazooka)
^
What have I done wrong ?

Using a lambda, would be like this (instead of std::bind())
[&](Worms*x, const Ogre::FrameEvent&y) { return input.selectBazooka(x,y); }

The first argument of std::bind is a callable object. In your case, that should be &UserInput::selectBazooka. The object to be associated with a call to that member function (&input) goes afterwards (you reversed this order). Still, you have to use placeholders for the missing parameters:
std::bind(&UserInput::selectBazooka, &input, std::placeholders::_1, std::placeholders::_2)

Related

How to build a parameter pack without any input values, from variadric class template?

I have a class that will produce a set of values and pass them to callback, as defined by variadic template arguments:
template <typename... TResults>
class Statement
{
public:
using HandleValues = std::function<bool(TResults...)>;
void getValues(const HandleValues& hander);
}
My real code is templated SQL statement handler, so these are the types to be read from a database. For simplification, just imagine the values produced by these dummy methods:
// Some overloads exist that produce a value:
template <typename TRead>
struct Produce
{
static TRead value() {}
};
template <>
struct Produce<int>
{
static int value() { return 42; }
};
template <>
struct Produce<bool>
{
static bool value() { return true; }
};
In real code, these are conversion traits.
The problematic code is trying to put the produced values in the callback. I have tried this:
template <typename... TResults>
void Statement<TResults...>::getValues(const RowHandler& handler)
{
return handler((Produce<TResults>::value(), ...));
}
The error I get:
MSVC: error C2064: term does not evaluate to a function taking 1 arguments
GCC is more verbose:
./include/sqlite3++/Statement.h:84:3: required from 'void sqlitepp::Statement<TResults>::execute(const RowHandler&, TValRest ...) [with TValRest = {const char*}; TResults = {double, int}; sqlitepp::Statement<TResults>::RowHandler = std::function<bool(double, int)>]'
../build/examples/basic/BasicSQLite/BasicSQLite.cpp:52:5: required from here
../include/sqlite3++/Statement.h:94:19: error: no match for call to '(const RowHandler {aka const std::function<bool(double, int)>}) (int)'
94 | return handler((ReadTraits<TResults>::ReadFromStatement(reader), ...));
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from c:\mingw\lib\gcc\mingw32\9.2.0\include\c++\functional:59,
from ../include/sqlite3++/internal/RawStatement.h:14,
from ../include/sqlite3++/Statement.h:5,
from ../build/examples/basic/BasicSQLite/BasicSQLite.cpp:6:
c:\mingw\lib\gcc\mingw32\9.2.0\include\c++\bits\std_function.h:685:5: note: candidate: '_Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = bool; _ArgTypes = {double, int}]'
685 | function<_Res(_ArgTypes...)>::
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
Clearly, the arguments are not actually expanding. I tried other variants, such as also putting ... after the template argument, but nothing has helped.
Use this return handler(Produce::value()...);

std::bind() throwing error when this is not passed

I am trying to understand std::bind(). I am trying to understand the code in the post https://riptutorial.com/cplusplus/example/7541/std--function-used-with-std--bind.
Code is as below.
#include <iostream>
#include <functional>
using namespace std;
class A
{
public:
std::function<void(int, const std::string&)> m_CbFunc = nullptr;
void foo()
{
if (m_CbFunc)
{
m_CbFunc(100, "event fired");
}
}
};
class B
{
public:
B(int x) : y(x)
{
auto aFunc = std::bind(&B::eventHandler, this, std::placeholders::_1, std::placeholders::_2);
anObjA.m_CbFunc = aFunc;
}
void eventHandler(int i, const std::string& s)
{
std::cout << s << ": " << i << std::endl;
}
void DoSomethingOnA()
{
anObjA.foo();
}
int y;
A anObjA;
};
int main(int argc, char *argv[])
{
B anObjB(4);
anObjB.DoSomethingOnA();
}
I couldn't understand why we are using this in bind call
auto aFunc = std::bind(&B::eventHandler, this, std::placeholders::_1, std::placeholders::_2)
eventHandler is taking 2 parameters and we are binding with placeholders. Not sure why do we need to pass this. If I remove this, I am getting below error.
/usr/include/c++/6/functional:1286:7: error: static assertion failed: Wrong number of arguments for pointer-to-member
static_assert(_Varargs::value
^~~~~~~~~~~~~
main.cpp: In constructor ‘B::B(int)’:
main.cpp:34:27: error: no match for ‘operator=’ (operand types are ‘std::function&)>’ and ‘std::_Bind&)>(std::_Placeholder<1>, std::_Placeholder<2>)>’)
anObjA.m_CbFunc = aFunc;
^~~~~
In file included from main.cpp:10:0:
/usr/include/c++/6/functional:1929:7: note: candidate: std::function<_Res(_ArgTypes ...)>& std::function<_Res(_ArgTypes ...)>::operator=(const std::function<_Res(_ArgTypes ...)>&) [with _Res = void; _ArgTypes = {int, const std::basic_string, std::allocator >&}]
operator=(const function& __x)
^~~~~~~~
The this is needed because eventHandler() is not a static method. std::bind() is used specifically when you want to use non-static methods of your class.
Note that personally, I find it ugly and don't like using it. I use lambdas instead.
anObjA.m_CbFunc = [=](int i, const std::string&s) { eventHandler(i,s); };
Even though the syntax for lambdas is kind of ugly, I don't think it's as ugly or obscure as bind. But that's just my preference.

C++17 Cannot use std::bind to produce a std::function

I have a Register function which takes a std::function<void(const uint8_t* data, size_t len)> as a parameter. I want to use the member function of an object as the target.
I found this question according to which the answer is to use std::bind to bind the first first argument (the implicit this pointer) to the actual object pointer and then use it as the std::function argument.
This however doesn't work anymore in neither C++11, C++14 nor C++17?
Consider the following test program.
#include <iostream>
#include <cstdint>
#include <functional>
void Register(std::function<void(const uint8_t* data, size_t len)> func) {
//Dummy - directly call into function
func(nullptr, 0);
}
class TestClass {
public:
void TestRegister() {
Register(
std::bind(&TestClass::TestTarget, this, std::placeholders::_1)
);
}
void TestTarget(const uint8_t* data, size_t len) {
(void) data;
(void) len;
std::cout << "Hello there" << std::endl;
}
};
int main() {
TestClass testObj;
testObj.TestRegister();
return 0;
}
When compiling for -std=c++17 this throws a rather cryptic error message (I have no idea what it's trying to say here with Wrong number of arguments for pointer-to-member):
In file included from /home/max/Documents/TestingFunctions/main.cpp:3:0:
/usr/include/c++/7/functional: In instantiation of ‘struct std::_Bind_check_arity<void (TestClass::*)(const unsigned char*, long unsigned int), TestClass*, const std::_Placeholder<1>&>’:
/usr/include/c++/7/functional:854:12: required from ‘struct std::_Bind_helper<false, void (TestClass::*)(const unsigned char*, long unsigned int), TestClass*, const std::_Placeholder<1>&>’
/usr/include/c++/7/functional:875:5: required by substitution of ‘template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...) [with _Func = void (TestClass::*)(const unsigned char*, long unsigned int); _BoundArgs = {TestClass*, const std::_Placeholder<1>&}]’
/home/max/Documents/TestingFunctions/main.cpp:14:78: required from here
/usr/include/c++/7/functional:841:7: error: static assertion failed: Wrong number of arguments for pointer-to-member
static_assert(_Varargs::value
^~~~~~~~~~~~~
/home/max/Documents/TestingFunctions/main.cpp: In member function ‘void TestClass::TestRegister()’:
/home/max/Documents/TestingFunctions/main.cpp:14:26: error: could not convert ‘std::bind(_Func&&, _BoundArgs&& ...) [with _Func = void (TestClass::*)(const unsigned char*, long unsigned int); _BoundArgs = {TestClass*, const std::_Placeholder<1>&}; typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type = std::_Bind<void (TestClass::*(TestClass*, std::_Placeholder<1>))(const unsigned char*, long unsigned int)>](((TestClass*)this), std::placeholders::_1)’ from ‘std::_Bind_helper<false, void (TestClass::*)(const unsigned char*, long unsigned int), TestClass*, const std::_Placeholder<1>&>::type {aka std::_Bind<void (TestClass::*(TestClass*, std::_Placeholder<1>))(const unsigned char*, long unsigned int)>}’ to ‘std::function<void(const unsigned char*, long unsigned int)>’
std::bind(&TestClass::TestTarget, this, std::placeholders::_1)
~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Replacing the TestRegister function with one that does the exact same thing in a lambda expression compiles and runs without problems.
void TestRegister() {
Register(
[this](const uint8_t* data, size_t len) {
TestTarget(data, len);
}
);
}
Question: Why does the std::bind approach from the linked question not work? Was this feature removed or do I have an error in my code?
Your function Register expects a function with two parameters, but you try to pass to it a function with one placeholded parameter.
void TestRegister() {
Register(
std::bind(&TestClass::TestTarget, this, std::placeholders::_1, std::placeholders::_2)
);
}
Your function takes two parameters, while you are only passing one placeholder.
std::bind(&TestClass::TestTarget, this, std::placeholders::_1, std::placeholders::_2);

How to use bind correctly here?

I can not figure out the correct syntax to bind member functions.
If I have a function that takes a function with a single argument,
how do I pass an object to it?
In the following example, what would be the correct syntax of passing the function?
#include <iostream>
#include <functional>
void caller(std::function<void(int)> f)
{
f(42);
}
class foo
{
public:
void f(int x)
{
std::cout<<x<<std::endl;
}
};
int main()
{
foo obj;
caller(std::bind(&foo::f,obj));
//^Wrong
}
Error was:
a.cpp: In function ‘int main()’:
a.cpp:18:34: error: could not convert ‘std::bind(_Func&&, _BoundArgs&& ...) [with _Func = void (foo::*)(int); _BoundArgs = {foo&}; typename std::_Bind_helper<std::__or_<std::is_integral<typename std::decay<_Tp>::type>, std::is_enum<typename std::decay<_Tp>::type> >::value, _Func, _BoundArgs ...>::type = std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo)>]((* & obj))’ from ‘std::_Bind_helper<false, void (foo::*)(int), foo&>::type {aka std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo)>}’ to ‘std::function<void(int)>’
caller(std::bind(&foo::f,obj));
Placeholders create a "space" for the actual arguments to be bound later:
int main()
{
foo obj;
caller(std::bind(&foo::f, &obj, std::placeholders::_1));
// ^ placeholder
// ^ address or even foo()
}
These placeholders are needed to correctly generate an appropriate signature for the std::bind result to be bound to the std::function<void(int)>.
You may also want to use the address of your object, or std::ref (so it won't be copied); this will vary on what you want the semantics to be.
There is an implicit first argument to member functions, which is the this point. You need to send it as a pointer; you also need a placeholder for the int argument. So:
caller(std::bind(&foo::f, &obj, std::placeholders::_1));
// ^ ^^^^^^^^^^^^^^^^^^^^^^^
You need to specify that the created function object takes a parameter using a placeholder:
std::bind(&foo::f,obj, std::placeholders::_1)

boost::shared_ptr and Return Type Resolver idiom

I am currently working on a concept of Object known in Java or C# for C++. It would be similar to variant type like boost::any, however having wider functionality. For that purpose I am using boost::shared_ptr to internaly store actual data and I wanted to provide Return Type Resolver idiom for easily obtaining this data, as it is stored in actual implementation. I know I could use boost::shared_ptr automatic conversion during assigment operator or constructor but as I said shared_ptr is not avaiable at this stage.
Implementing RtR I have encountered a problem with linux platform. For simplicity of code I provide just a simple code which reflects what I want to do basically and what is working under VS2010 and not under GCC. Any comments or solutions woud be appriciate.
struct RtR
{
template<typename Ptr>
operator Ptr()
{
return Ptr();
}
template<typename Ptr>
operator Ptr() const
{
return Ptr();
}
};
class TestRtR
{
void test()
{
boost::shared_ptr<int> intPtr(new int);
intPtr = get();
}
void test() const
{
boost::shared_ptr<const int> intPtr(new int);
intPtr = get();
}
RtR get()
{
RtR ret;
return ret;
}
const RtR get() const
{
const RtR ret;
return ret;
}
};
As I said - if You compile it under VS2010 everything goes ok, but under linux I get:
In member function ‘void TestRtR::test()':
error: ambiguous overload for ‘operator=’ in ‘intPtr = TestRtR::get()’
note: candidates are:
note: boost::shared_ptr<T>& boost::shared_ptr<T>::operator=(const boost::shared_ptr<T>&) [with T = int, boost::shared_ptr<T> = boost::shared_ptr<int>]
note: boost::shared_ptr<T>& boost::shared_ptr<T>::operator=(boost::shared_ptr<T>&&) [with T = int, boost::shared_ptr<T> = boost::shared_ptr<int>]
note: boost::shared_ptr<T>& boost::shared_ptr<T>::operator=(boost::detail::sp_nullptr_t) [with T = int, boost::shared_ptr<T> = boost::shared_ptr<int>, boost::detail::sp_nullptr_t = std::nullptr_t]
In member function ‘void TestRtR::test() const’:
error: ambiguous overload for ‘operator=’ in ‘intPtr = TestRtR::get()’
note: candidates are:
note: boost::shared_ptr<T>& boost::shared_ptr<T>::operator=(const boost::shared_ptr<T>&) [with T = const int, boost::shared_ptr<T> = boost::shared_ptr<const int>]
note: boost::shared_ptr<T>& boost::shared_ptr<T>::operator=(boost::shared_ptr<T>&&) [with T = const int, boost::shared_ptr<T> = boost::shared_ptr<const int>]
note: boost::shared_ptr<T>& boost::shared_ptr<T>::operator=(boost::detail::sp_nullptr_t) [with T = const int, boost::shared_ptr<T> = boost::shared_ptr<const int>, boost::detail::sp_nullptr_t = std::nullptr_t]
Are definitions of boost::shared_ptr different under GCC and VS2010? What is the ground of this ambiguity and how to solve it?