简体   繁体   中英

Pointer-to-member-function error

I am trying to use a pointer to a member function in my code so that I can easily replace the function to use without changing everywhere in the code. I get an error while compiling that I don't understand how to solve. Here is a minimum working example:

OrderBook.h

#include <list>
#include <string>

class Order
{

};

class OrderBook
{
    typedef void(OrderBook::* MatchingAlgorithm)(Order&, std::list<Order>&);
public:
    OrderBook(const std::string name);    
    void ExecuteFunction(Order&, std::list<Order>);
private:
    void FunctionToUse(Order&, std::list<Order>&);        
    const std::string m_OrderBookName;
    MatchingAlgorithm m_matchingAlgorithm;
};

OrderBook.cpp

#include "OrderBook.h"

OrderBook::OrderBook(
    const std::string name
    )
    : m_OrderBookName(name)
{
    m_matchingAlgorithm = &OrderBook::FunctionToUse;
}

void OrderBook::ExecuteFunction(Order & order, std::list<Order> listOfOrders)
{
    (*m_matchingAlgorithm)(order, listOfOrders);
}

void OrderBook::FunctionToUse(Order &, std::list<Order>&)
{
    // do nothing
}

Source.cpp

#include "OrderBook.h"

int main() 
{
    std::list<Order> mylist;
    Order o1, o2;    
    mylist.push_back(o1);
    mylist.push_back(o2);

    OrderBook ob("my book");

    ob.ExecuteFunction(o1, mylist);

    return 0;
}

Compilation Errors

error C2171: '*': illegal on operands of type 'OrderBook::MatchingAlgorithm'
error C2064: term does not evaluate to a function taking 2 arguments

If I replace (*m_matchingAlgorithm) with FunctionToUse inside ExecuteFunction the code compiles without errors.

将函数调用更改为:

(this->*m_matchingAlgorithm)(order, listOfOrders);

Short answer

You can call your function using the pointer to member operator ( .* or ->* ):

void OrderBook::ExecuteFunction(Order & order, std::list<Order> listOfOrders)
{
    (this->*m_matchingAlgorithm)(order, listOfOrders);
}

More info here .

Long explanations

We are all used to omit this-> for accessing members of the current object. The mecanism that allows this is name resolution principles. But these do not apply for pointer dereferencing operators.

The simple case of a pointer to a data member

Let's star with a simpler case : a pointer to an integer member.

class OrederBook {
    ...
    int x,y; 
    int OrderBook::* px; 
};

In the constructor you couldn't initialize px with &x because &x is an absolute address of an integer, and px is the (relative) address of an integer in an OrderBook . We would then initialize it:

OrderBook::OrderBook(..)
    : m_OrderBookName(name), px(&OrderBook::x) {...}

But in this case, the ordinary dereferencing operator for px would not work either:

 *px =2;    // error because of unary operator *

In fact, for dereferencing such a pointer, you need to know not only the pointer, but also the object in which this pointer should be used:

 this->*px =2;    // yes ! take relative px address and apply it to this object.  

Unary vs. Binary derefencing

The standard defines two different dereferencing operators:

5.3.1/1: The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points. If the type of the expression is “pointer to T,” the type of the result is “T.”

5.5/3: The binary operator ->* binds its second operand, which shall be of type “pointer to member of T” to its first operand, which shall be of type “pointer to T” or “pointer to a class of which T is an unambiguous and accessible base class.” The expression E1-> E2 is converted into the equivalent form ( (E1)).*E2.

Dereferencing a pointer to a member function

For the data example above, you have the choice of the weapons. You could build very easily code achieving the same results, but defining px as int *px instead of int OrderBook::*px and using the unary * as usual.

Unfortunately for poitners to non static member function, you can't use such shortcuts. You really need a pointer to a member function and not a pointer to a function: When you call a member function, in addition to the arguments that you have to pass, you always have to know for which object you call it. And the only way to tell this is to use (->*) or (.*) .

Conclusion

Ommitting this->* and assuming the compiler would be intelligent enough to deduct that it's for the current object could seem natural for us. But this is not defined by the standard. It's unfortunate and more here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM