Reputation: 1077
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
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
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)
Upvotes: 2