I'd like to store a function pointer to a private member function of my object inside my class.
Basically I want to do this:
MyWindow::MyWindow()
{
std::function<void(int&)> func = this->memberFunction; // ERROR
}
void MyWindow::memberFunction(int& i)
{
// do something
}
When I try to build it the compiler throws an error:
Error C3867: 'MyWindow::memberFunction': non-standard syntax; use '&' to create a pointer to member
The error message for C3867 tells you the first problem: you need to use & to form a function pointer.
Your next problem is that you do not have a function pointer, but a pointer-to-member-function, and that is not compatible with your std::function, which is missing anywhere to store or pass the implicit first argument that holds the "this" pointer.
You can, however, "bind" a value for that argument, in effect hardcoding it into the functor.
You're also going to need to spell it MyWindow::memberFunction rather than this->memberFunction, because that's just the way it is (to quote GCC: "ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function").
So:
using std::placeholders;
std::function<void(int&)> func = std::bind(&MyWindow::memberFunction, this, _1);
Or, using modern techniques:
std::function<void(int&)> func = [this](int& x) { memberFunction(x); };
Or just:
auto func = [this](int& x) { memberFunction(x); };
Related
I would like to pass function pointer as a function parameter.
Here is my code:
void AuthServerOpcodes::ValidateAndSetServerOpcode(ServerOpcode serverOpcode, void(*handlerFunc(std::vector<std::byte> data))) {}
Here is the function I would like to pass as second parameter in ValidateAndSetServerOpcode:
void AuthServerOpcodes::Test(std::vector<std::byte> data) {
std::cout << "all good" << std:end
}
Here is how I try to pass it:
ValidateAndSetServerOpcode(SMSG_LOGIN_REQUEST, &Test);
However this seems to be not the correct way. When I try to do it in that way I get error:
Cannot initialize a parameter of type 'void (*(*)
(std::vector<std::byte>))' with an rvalue of type 'void
(AuthServerOpcodes::*)(std::vector<std::byte>)': different return type
('void (*)' vs 'void')
Why is that and how can I fix it?
Pointers to member must be qualified with the class type, so you need to get the pointer you'll need to use
ValidateAndSetServerOpcode(SMSG_LOGIN_REQUEST, &AuthServerOpcodes::Test);
But it looks like you've tried that in the previous edit, so I guess you've called the function pointer to member incorrectly. You didn't show a minimal, reproducible example so I can't help you more, please create one. Anyway I've created a compiled example on Compiler Explorer
typedef void (AuthServerOpcodes::*HandlerFunc)(std::vector<std::byte> &);
void AuthServerOpcodes::ValidateAndSetServerOpcode(ServerOpcode serverOpcode,
HandlerFunc handlerFunc)
{
std::vector<std::byte> myVector;
(this->*handlerFunc)(myVector); // call the hander
}
void FreeStandingFunction(AuthServerOpcodes& opc,
AuthServerOpcodes::HandlerFunc handlerFunc,
std::vector<std::byte> &data)
{
(opc.*handlerFunc)(data);
}
As you can see the pointer to member must be called with ->* or .* and the whole dereferencing must be wrapped inside () because those operators has lower precedence than the function call operator ()
See also Function pointer to member function
Some off-topic note:
Don't use lines that are too long like that
Don't pass vectors by values unless you really need to preserve the outside value. Always pass by reference with const std::vector<>& (or remove const to modify the outside variable)
Use '\n' instead of std::endl
You can't do that.
There is no function pointer to that function, because it is a member function.
You can instead pass a pointer-to-member-function, or better yet a std::function bound to a lambda that captures the this pointer.
It's just a type mismatch, your function is a method of the AccountManager class,
so it has this signature similar to:
static void Login(AccountManager *this, std::vector<..> data);
You can either detach function from class, change your type definition of handlerFunc or consider different techniques like std::mem_fn or std:bind
https://en.cppreference.com/w/cpp/utility/functional/mem_fn
https://en.cppreference.com/w/cpp/utility/functional/bind
Here's the code:
#include <iostream>
#include <thread>
struct PickRandomFile {
PickRandomFile() {
std::thread t1(taskScanPaths);
}
inline void taskScanPaths() {
// my task
}
};
int main() {
PickRandomFile pickRandomFile;
return 0;
}
msvc says PickRandomFile::taskScanPaths': non-standard syntax; use '&' to create a pointer to member ThreadTrigger
What's wrong? I usually do it in gcc.
Free functions "decay to pointers" (similar to arrays) so
std::thread t1(taskScanPaths);
would have been ok if taskScanPaths was a free function and it would have same effect as
std::thread t1(&taskScanPaths);
However, for class member function you need the address-of to get a pointer to the member function (and you need to specify the class), as in
std::thread t1(&PickRandomFile::taskScanPaths,this);
Also note that you need to pass a object/pointer to an instance so the thread can actually call the method.
Some relevant quotes from cppreference:
Pointer to member functions
A pointer to non-static member function f which is a member of class C
can be initialized with the expression &C::f exactly. Expressions such
as &(C::f) or &f inside C's member function do not form pointers to
member functions.
It does not explicitly mention f, but as &f does not form a pointer to member function, it is kinda safe to assume f also does not form a pointer to member function.
On the other hand:
Pointers to functions
A pointer to function can be initialized with an address of a
non-member function or a static member function. Because of the
function-to-pointer implicit conversion, the address-of operator is
optional:
I am trying to set a delegate for a function and have the 2 following classes to achieve that.
On the bottom is the error I'm getting. How do I handle it?
Class A
typedef void (*SocketEventString) (String);
class SocketIO
{
public:
SocketIO();
void onMessage(SocketEventString _cb);
private:
SocketEventString _onMessage;
};
Class B
class BoardManager
{
public:
BoardManager();
void handleAction(String action);
SocketIO io;
};
//Constructor
BoardManager::BoardManager() {
io.onMessage( std::bind( &BoardManager::handleAction, this, std::placeholders::_1 ) );
}
ERROR
sketch/BoardManager.cpp: In member function 'void BoardManager::initializeSocketIO()':
BoardManager.cpp:68: error: no matching function for call to 'SocketIO::onMessage(std::_Bind_helper<false, void (BoardManager::*)(String), BoardManager* const, const std::_Placeholder<1>&>::type)'
io.onMessage( std::bind( &BoardManager::handleAction, this, std::placeholders::_1 ) );
^
sketch/BoardManager.cpp:68:90: note: candidate is:
In file included from sketch/BoardManager.h:10:0,
from sketch/BoardManager.cpp:8:
sketch/SocketIO.h:25:18: note: void SocketIO::onMessage(SocketEventString)
void onMessage(SocketEventString _cb);
The std::bind function return an object that is not compatible or convertible to a pointer to a non-member function.
Instead use std::function:
using SocketEventString = std::function<void(String)>;
With the definition
typedef void (*SocketEventString) (String);
you say that SocketEventString is a pointer to a non-member function (i.e. a function not a member in a class or struct) that takes one argument of type String and returns no value.
The std::bind function returns an object of an unknown class. That object is not the same a the pointer-type you define SocketEventString to be.
The two types (SocketEventString and the object returned by std::bind) are not compatible. You can not convert from one of the types to the other.
The compiler tell you this, because it tries to find a function SocketIO::onMessage which takes the type of the object returned by std::bind and don't find any such overload.
Instead of the SocketEventString type you have defined, you need to use type that is compatible with the object returned by std::bind. That's what I have shown above in my answer, defined SocketEventString to be a different type, a type that is compatible with the type returned by std::bind.
Firstly, you can't use a C function pointer for a C++ function binding like that. Essentially, when you use bind it captures some variables to be used in the function call (such as this), so you need to use std::function which handles capturing variables if you want to bind a member function (because member functions at the very least need the this pointer captured). Also, in my opinion, std::bind is fairly ugly, and I recommend getting familiar the new C++ lambdas.
BoardManager::BoardManager() {
io.onMessage( [&]( String action ) {
handleAction( action );
});
}
I'm trying to run non-static member function in the other thread. If I go:
void *(PortManager::*innerAskPtr)() = &this->innerAsk;
QFuture<void> f = QtConcurrent::run(innerAskPtr);
it prompts that
ISO C++ forbids taking the adress of an unqualified or parenthesized non-static member function to form a pointer to member function.
but if I delete this extra reference symbol:
void *(PortManager::*innerAskPtr)() = this->innerAsk;
QFuture<void> f = QtConcurrent::run(innerAskPtr);
it goes that it
cannot convert 'PortManager::innerAsk' from type 'void (PortManager::)()' to type 'void* (PortManager::*)()`
What to add on the right side to get these extra stars (*) on the left?
But still, even if I would get there, there is always another error; about the run(T(*)()):
no matching function for call to 'run(void* (PortManager::*&)())
it's so over my head to understand how this reference got there...
The documentation for QtConcurrent::run seems to explain all this.
Using Member Functions
QtConcurrent::run() also accepts pointers to member functions. The first argument must be either a const reference or a pointer to an instance of the class. Passing by const reference is useful when calling const member functions; passing by pointer is useful for calling non-const member functions that modify the instance.
There are code examples immediately following this text.
In your code:
void *(PortManager::*innerAskPtr)() = this->innerAsk;
QFuture<void> f = QtConcurrent::run(innerAskPtr);
the error message indicates that this->innerAsk returns void, but you are trying to assign it to a pointer-to-member-function returning void *. You probably meant:
void (PortManager::*innerAskPtr)() = &PortManager::innerAsk;
but you don't need to do this in order to call QtConcurrent::run, as the code examples show you can just write:
QtConcurrent::run( this, &PortManager::innerAsk );
I'm trying to assign a function pointer that is an argument in the constructor of a class to a private instance variable. (The purpose of this is to be able to pass a callback function to the constructor and use said callback function in member functions of the class.)
I thought I declared the instance variable correctly as a function pointer. The way I read the code snippet, the left operand "cmp" is a pointer, not a function, just like the right operand. (Both are pointers to functions of the same type, or so I thought.) However, the error message says "function as left operand." What am I doing wrong or misinterpreting? Is there a "most vexing parse" issue somewhere?
How can I fix this error and assign the function pointer?
I'm getting the following error message:
"error C2659: '=' : function as left operand"
The error is occurring in the following snippet of code:
template <typename Type>
PQueue<Type>::PQueue(int (cmpFn)(Type,Type))
{
cmp = cmpFn;
}
The compiler is complaining about
cmp = cmpFn;
The constructor prototype is
PQueue(int (cmpFn)(Type, Type) = OperatorCmp);
(OperatorCmp is just another function pointer.)
I declared the instance variable in the private section as
int (cmp)(Type, Type);
The IDE I'm using is Visual C++ 2008 Express, if that matters. (using old version to be compatible with old course materials).
The declaration
int (cmp)(Type, Type);
indeed declares a function, not a function pointer. However, the same syntax used in the parameter list for a function declaration denotes a function pointer, so cmpFn is in fact of type int (*)(Type, Type). Just change the declaration for cmp to
int (*cmp)(Type, Type);
and you'll be good.