Search code examples
c++function-pointers

Calling a member function pointer without using this


I've written the following class that looks up a keyword and executes the associated function.

#include <iostream>
#include <string>
#include <map>
class Example;

typedef std::map<
    std::string, void (Example::*)(const std::string &)> ExampleList;
typedef ExampleList::iterator ExampleIter;

class Example
{
public:
    ExampleList lut;
    Example()
    {
        lut["aaa"] = &Example::aaa;
        lut["bbb"] = &Example::bbb;
    }

    void lookup(const std::string& line)
    {
        // Get the keyword
        std::size_t keylen = line.find(' ', 0);
        std::string keyword = line;
        if (keylen != line.npos)
            keyword = line.substr(0, keylen);

        // Is it something we recognize
        ExampleIter eit = lut.find(keyword);
        if (eit == lut.end())
        {
            std::cout << "Unable to handle " << keyword << std::endl;
            return;
        }

        // Found - execute the handler
        (this->*(eit->second))(line);  // << is there an alternative syntax without this?
    }

    void aaa(const std::string& info)
    {
        std::cout << "aaa" << std::endl;
    }
    void bbb(const std::string& info)
    {
        std::cout << "bbb" << std::endl;
    }
};

int main()
{
    Example eg;
    eg.lookup("aaa");    // pass
    eg.lookup("bbb is legal"); // pass
    eg.lookup("bbbb is illegal"); // fail - bbbb not found
    eg.lookup("cc"); // fail cc not found
    eg.lookup("aaaa"); // fail aaaa not found 
}

At the end of the function lookup, I am executing the handler using

(this->*(eit->second))(line);

I'm just wondering whether it is possible to call the handler without this->*


Solution

  • No: pointers to members, even to members of the current class type, do not have the implicit (*this). that the members themselves have (or rather the (*this).* they would need). Fundamentally, this is because it would be impossible to (reliably) distinguish between use of the pointer and use of the referenced member:

    struct X {
      int i;
      auto f() {
        int X::*p=&X::i;
        return p;  // does this return 'int X::*' or 'int'?
      }
    };
    

    This ambiguity can't arise with direct member access precisely because you have to use &X::i rather than just &i to form a pointer-to-member. Consider also that such a pointer-to-member might point to a member of a derived class that *this doesn't even have.