1

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->*

10
  • 3
    No, is the short answer. But you could redesign to avoid using member function pointers. Maybe use std::function instead. Commented Sep 30, 2023 at 5:56
  • 1
    std::invoke(eit->second, this, line);. You still need to specify this. Commented Sep 30, 2023 at 6:02
  • 2
    How else do you expect the pointed-to member function to receive the correct object? Commented Sep 30, 2023 at 6:17
  • 1
    With static member functions you could Commented Sep 30, 2023 at 6:23
  • 1
    Style note: rather than using typedef... using ExampleList = std::map<std::string, void (Example::*)(const std::string &)>; using ExampleIter = ExampleList::iterator; Commented Sep 30, 2023 at 6:27

1 Answer 1

0

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.