function pointers using functions in an object with parameters - c++

I have been playing around with function pointers in c++ and seem to have found a bit of a problem. I made a demo to reproduce the error in a simple example.
I have the header file
class MyClass
{
public:
void MyFunction(int i);
MyClass();
~MyClass();
};
and the cpp file
#include "MyClass.h"
#include <iostream>
#include <functional>
using namespace std;
MyClass::MyClass()
{
//doesn't work
function<void(int)> func = &MyClass::MyFunction;
}
void MyClass::MyFunction(int i)
{
cout << i << endl;
}
In the constructor of the cpp file I am trying to create a pointer to MyFunction. It gives the error error C2664: 'void std::_Func_class<_Ret,int>::_Set(std::_Func_base<_Ret,int> *)' : cannot convert argument 1 from '_Myimpl *' to 'std::_Func_base<_Ret,int> *' in the functional file at line 506. It works fine with a parameterless method, but not with them. Does anyone know why, and how to resolve it?

You can use this and bind the object being constructed to the function. For instance, if your constructor looked like this:
MyClass::MyClass()
{
function<void(int)> func = bind(&MyClass::MyFunction, this, placeholders::_1);
func(6);
}
And you created a MyClass instance:
MyClass instance;
Then 6 will be printed to stdout.

You can also use std::mem_fn in C++11, which wraps a member function/variable into a callable closure
#include <iostream>
#include <functional>
class MyClass
{
public:
MyClass()
{
auto func = std::mem_fn(&MyClass::MyFunction);
func(this, 42); // call it on the current instance
}
void MyFunction(int i)
{
std::cout << i << std::endl;
}
};
int main()
{
MyClass foo;
}
or, you can explicitly specify the instance you're calling the pointer to member function
MyClass()
{
auto func = &MyClass::MyFunction;
(this->*func)(42); // call it on the current instance
}
In particular, note that std::function<void(int)> is not convertible to a pointer to member function. See related Using generic std::function objects with member functions in one class
That's why using auto with std::mem_fn gets rid of all the pain.

Related

function pointer to overloaded static member - to use as custom deleter in unique_ptr

I have a class with static and overloaded member function.
I want to use one them as a custom deleter in a unique_ptr
there are lots of questions on this topic, none of them worked for me.
#include <iostream>
#include <memory>
#include <functional>
class A {
public:
static void release() {
std::cout << "void released\n";
}
static void release(int*i) {
std::cout << *i << " released\n";
}
};
int main()
{
int i = 10;
std::unique_ptr<int, decltype(&A::release(int*))> ptr(&i, &A::release); // compiler error
std::unique_ptr<int, std::function<void(int*)>> ptr(&i, &A::release); // compiler error
return 0;
}
try it out here: https://onlinegdb.com/H14txk3sL
std::unique_ptr<int, void(*)(int*)> ptr(&i, &A::release);
// ~~~~~~~~~~~~^
This way, std::unique_ptr's constructor will expect a specific type of a pointer, which will help the compiler resolve ambiguity.
This:
decltype(&A::release(int*))
is not a valid syntax. In order yo use decltype(e), you'd have to write decltype(&A::release), but this again would raise an ambiguity error, and so it would have to become:
decltype(static_cast<void(*)(int*)>(&A::release))
but that's a long-winded way of saying void(*)(int*).
This:
std::function<void(int*)>
doesn't help in resolving ambiguity, becuase std::functions's constructor is a template as well, which means the compiler again misses a context that would help it to choose one of the overloaded functions.

Default constructor that calls peer constructor with unique_ptr move

I am trying to make a class with two constructors. One that is a default constructor, the other calling the parameterized constructor. I get a compiler error that tells me that I cannot use move on the object just created and I sort of understand that it doesn't like to do that, because there is no real assignment here.
How can I achieve the right behavior? I am trying to avoid writing two constructors that initialize the variables. An initialization function might work, but then I would have to fill the body of the constructors and I was trying to come up with a neat solution like shown below.
#include <string>
#include <iostream>
#include <memory>
using namespace std;
class Foo
{
public:
Foo(unique_ptr<int>& number) : m_number(move(number))
{
}
Foo() : Foo(make_unique<int>(54))
{
}
void print()
{
cout << m_number << endl;
}
private:
unique_ptr<int> m_number;
};
int main()
{
Foo f;
f.print();
return 0;
}
main.cpp:18:33: error: invalid initialization of non-const reference
of type ‘std::unique_ptr&’ from an rvalue of type
‘std::_MakeUniq::__single_object {aka std::unique_ptr}’
Foo() : Foo(make_unique(54))
I decided to go for an rvalue constructor. This seems to resolve the issue for me.
#include <string>
#include <iostream>
#include <memory>
using namespace std;
class Foo
{
public:
// rvalue constructor so that we can move the unique_ptr.
Foo(unique_ptr<int>&& number) : m_number(move(number))
{
}
Foo() : Foo(make_unique<int>(54))
{
}
void print()
{
cout << *m_number << endl;
}
private:
unique_ptr<int> m_number;
};
int main()
{
Foo f;
f.print();
unique_ptr<int> a = make_unique<int>(33);
Foo f2(move(a)); // important to do a move here, because we need an rvalue.
f2.print();
return 0;
}

Converting pointer to member function to std::function

I have a slightly convoluted use case of passing a member function pointer to an outside function which is then called again by a member function (Don't ask!). I'm learning about std::function and std::mem_fn but I can't seem to be able to convert my old school function pointer
void (T::*func)(int) to a std::function<void (T::*)(int) func>
in the code below, I'd like to be able to pass a std::function to memFuncTaker in the call from anotherMember
#include "class2.hpp"
#include <iostream>
class outer{
public:
void aMember(int a){
std::cout << a <<std::endl;
}
void anotherMember(double){
memFuncTaker(this, &outer::aMember);
}
};
template<class T>
void memFuncTaker(T* obj , void (T::*func)(int) ){
(obj->*func)(7);
}
When you bind std::function to a non-static member function pointer, it "reveals" the hidden this parameter, making it the first explicit parameter of the resultant functor. So in your case for outer::aMember you'd use std::function<void(outer *, int)> and end up with a two-parameter functor
#include <functional>
#include <iostream>
template<class T>
void memFuncTaker(T *obj , std::function<void(T *, int)> func){
func(obj, 7);
}
class outer{
public:
void aMember(int a){
std::cout << a <<std::endl;
}
void anotherMember(double){
memFuncTaker(this, std::function<void(outer *, int)>{&outer::aMember});
}
};
int main() {
outer o;
o.anotherMember(0);
}
http://coliru.stacked-crooked.com/a/5e9d2486c4c45138
Of course, if you prefer, you can bind the first argument of that functor (by using std::bind or lambda) and thus "hide" it again
#include <functional>
#include <iostream>
using namespace std::placeholders;
void memFuncTaker(std::function<void(int)> func){
func(7);
}
class outer{
public:
void aMember(int a){
std::cout << a <<std::endl;
}
void anotherMember(double){
memFuncTaker(std::function<void(int)>(std::bind(&outer::aMember, this, _1)));
}
};
int main() {
outer o;
o.anotherMember(0);
}
Note that in this version memFuncTaker no longer has to be a template (which happens to be one of the primary purposes of std::function - employ type erasure techniques to "de-templatize" the code).

How to pass a non-static member function as a unique_ptr deleter [duplicate]

This question already has answers here:
How Can I Pass a Member Function to a Function Pointer?
(3 answers)
Closed 7 years ago.
#include <memory>
#include <iostream>
#include <exception>
#include <curl/curl.h>
class client
{
private:
std::unique_ptr<CURL, decltype(&psclient::del_curl)> uptr_curl_;
inline CURL * init_curl()
{
CURLcode result = curl_global_init(CURL_GLOBAL_DEFAULT);
if(result != CURLE_OK)
throw std::logic_error(curl_easy_strerror(result));
return curl_easy_init();
}
inline void del_curl(CURL * ptr_curl)
{
curl_easy_cleanup(ptr_curl);
curl_global_cleanup();
}
public:
inline client()
: uptr_curl_(init_curl(), &client::del_curl)
{
}
}
The compiler keeps complaining No matching constructor for initialization of 'std::unique_ptr<CURL, void (*)(CURL *)>'
It seems to me like the declaration is correct for the deleter template argument. It is a function pointer that returns void and takes a CURL * as an argument. This matches the signature of del_curl.
Is there yet another random rule, unknown to me, in C++ that specifies a requirement for template arguments to non-static member function pointers? If so, why?
The answer of #R. Sahu is correct imo. However, if you insist of passing a non-static member function deleter, here is a way of doing it using the good old std::bind and std::function:
#include <memory>
#include <iostream>
#include <functional>
class Foo
{
private:
std::unique_ptr<int, std::function<void(int*)>> _up;
public:
Foo(): _up(new int[42], std::bind(&Foo::deleter, this, std::placeholders::_1))
{
}
void deleter(int* p)
{
delete[] p;
std::cout << "In deleter" << std::endl;
}
};
int main()
{
Foo foo;
}
PS: I just don't like the bind, I wonder if one can improve on that.
With a lambda:
Foo(): _up(new int[42],
[this](int* p)->void
{
deleter(p);
}
){}
The second template parameter used in the declaration of uptr_curl_ is void (*)(CURL *)
The type of &client::del_curl is void (CURL::*)(CURL*).
They are not the same. You can change del_curl to a static member function. That will resolve the problem.
Update
You can use a non-static member function with the help of std::function and std::bind.
class client
{
public:
client();
private:
std::unique_ptr<CURL, std::function<void(CURL *)>> uptr_curl_;
CURL * init_curl();
void del_curl(CURL * ptr_curl);
};
client::client() : uptr_curl_(init_curl(),
std::bind(&client::del_curl, this, std::placeholders::_1))
{
// ...
}

How do I use a method as an argument for another method?

#include <functional>
#include <iostream>
class Foo{
void print(std::function<void (void)> f){
f();
std::cout << "!";
}
void sayHello(){
std::cout << "Hello";
}
public:
void tell(){
print(sayHello);
}
};
int main(){
auto foo = Foo();
foo.tell(); // 'Foo::sayHello': function call missing argument list; use '&Foo::sayHello' to create a pointer to member
}
I am getting the error C3867: 'Foo::sayHello': function call missing argument list; use '&Foo::sayHello' to create a pointer to member. If I use &Foo::sayHello then I'll get a bunch of templating errors.
What did I do wrong?
sayHello is a non-static member function, so it has an implicit first argument, the this pointer. The simplest way to get your code to work is to use a lambda expression that captures the this pointer.
void tell(){
print([this]{sayHello();});
}
Another option is std::bind
void tell(){
print(std::bind(&Foo::sayHello, this));
}
You want to pass a member function as argument, however a member function must be called on an object instance.
A possible solution is the following:
void tell(){
print(std::bind(&Foo::sayHello, this));
}
A member function has an additional parameter: the this pointer. You are just assuming the declaration of the function has none
void (void)
The bind() function can help you bind that pointer into it and return an object suitable for a std::function wrapper
#include <functional>
#include <iostream>
class Foo{
void print(std::function<void (void)> f){
f();
std::cout << "!";
}
void sayHello(){
std::cout << "Hello";
}
public:
void tell(){
print(std::bind(&Foo::sayHello, this));
}
};
int main(){
auto foo = Foo();
foo.tell();
}