cbel
cbel

Reputation: 1077

How can I std::bind the method of a base class in this situation?

class animal {
protected:
    animal() {}
    void eat(int x) {}
};


class human
    : private animal
{
public:
    typedef animal base_type;
    using base_type::eat;
};

class stomach {
public:
    stomach(std::function<void(int)> feed) {}
};

class lady
    : public human
{
public:
    typedef lady        this_type;
    typedef human       base_type;

    lady()
        : base_type()
        , m_Stomach(std::bind(&base_type::eat, this, std::placeholders::_1))
    {
    }

private:
    stomach m_Stomach;
};

If client code write down:

lady gaga;

The compiler complains that std::bind(&base_type::eat, ...) is error C2064: term does not evaluate to a function taking 2 arguments.

I had found that if the class lady is modified to:

class lady
    : public human
{
public:
    typedef lady        this_type;
    typedef human       base_type;

    lady()
        : base_type()
        , m_Stomach(std::bind(&this_type::help_eat, this, std::placeholders::_1))
    {
    }

private:
    void help_eat(int x)
    {
        base_type::eat(x);
    }
    stomach m_Stomach;
};

With a help function, the compiler will std::bind well. But the code duplicates.

I had also found if changing std::bind to lambda m_Stomach([&](int x){ base_type::eat(x); }), this can also been compiled.

My question is that is there a better way to use std::bind in this situation? If not, I maybe consider the lambda.

Upvotes: 4

Views: 940

Answers (2)

user2249683
user2249683

Reputation:

The animal is a private base class of human and although the using-declaration makes the function eat available it does not change the signature void (animal::*)(int) of the function.

From 7.3.3 The using declaration

For the purpose of overload resolution, the functions which are introduced by a using-declaration into a derived class will be treated as though they were members of the derived class. In particular, the implicit this parameter shall be treated as if it were a pointer to the derived class rather than to the base class. This has no effect on the type of the function, and in all other respects the function remains a member of the base class.

Hence, the binding (referring to the function type) leads to the error ‘animal’ is an inaccessible base of ‘lady’ (g++).

You can fix it by using a lambda m_Stomach([this](int x) { this->eat(x); }), replacing the using-declaration in human by void eat(int x) { base_type::eat(x); } or just do it your way.

Upvotes: 0

Daniel Frey
Daniel Frey

Reputation: 56863

Your problem is that animal is a private base class of human and therefore passing (and storing) this (which is of type lady*) can not be used to call the method from animal. You could fix it making it a public base or by adding a method to human:

animal* animal_ptr() { return this; }

and later bind:

std::bind(&base_type::eat, animal_ptr(), std::placeholders::_1)

Live example

Upvotes: 2

Related Questions