Background: I'm using a delegation technique to abstract access to arbitrary object methods, but I'm having some issues where the linker is concerned. Consider the following class, ContextNode
.
template <class ObjectType, class GetType, class SetType>
class ContextNode: public ContextNodeBase {
public:
ContextNode(ObjectType* target,
GetType (ObjectType::*getter)(void开发者_高级运维),
void (ObjectType::*setter)(const SetType& ref)
): _target(target), _getter(getter), _setter(setter) { }
virtual ~ContextNode(void) { }
virtual void r(Datum& value) {
value = (_target->*_getter)();
return;
}
virtual void w(const Datum& value) {
(_target->*_setter)(value);
return;
}
private:
ObjectType* _target;
GetType (ObjectType::*_getter)(void);
void (ObjectType::*_setter)(const SetType& ref);
};
The implementation of Datum
is irrelevant. Also consider the trivial class Thing
.
class Thing {
public:
Thing(void);
~Thing(void);
int getValue(void) { return _value; }
void setValue(const int& x) { _value = x; }
private:
int _value;
};
The problem: I can construct instantiations of ContextNode
like so.
Thing* thing = new Thing();
ContextNode<Thing,int,int>* cn = new ContextNode<Thing,int,int>(thing, &Thing::getValue, &Thing::setValue);
This works well for my needs. I run into issues though, with overloaded methods. Assume I had written instead:
class Thing {
public:
Thing(void);
~Thing(void);
int value(void) { return _value; }
void value(const int& x) { _value = x; }
private:
int _value;
};
Thing* thing = new Thing();
ContextNode<Thing,int,int>* cn = new ContextNode<Thing,int,int>(thing, &Thing::value, &Thing::value);
This fails to link. The issue, I believe, is that the linker is attempting name-based resolution only, thus I see <unresolved overloaded function type>
errors.
My question: is there some syntax sugar to explicitly specify to which of several overloaded methods I'm referring? I can't imagine that such a silly quirk would break such an elegant solution. I've been able to find nothing online, nor on the C++ FAQ, nor right here on SO regarding the topic.
What's the fix, or am I hosed?
You can use a cast to disambiguate an overloaded function name:
(int (Thing::*)(void))(&Thing::value)
(void (Thing::*)(const int&))(&Thing::value)
It might also be possible to provide utility functions that select one or another of the overloads.
//enjoy the syntax: function accepting and returning a pointer to member function
template <class Object, class T>
T (Object::*as_getter(T (Object::*f)()))()
{
return f;
}
template <class Object, class T>
void (Object::*as_setter(void (Object::*f)(T)))(T)
{
return f;
}
class Thing {
public:
Thing(void);
~Thing(void);
int value(void) { return _value; }
void value(const int& x) { _value = x; }
private:
int _value;
};
template <class F>
void foo(F f)
{}
int main()
{
foo(as_getter(&Thing::value)); //selects methods of kind X Y::zzz()
foo(as_setter(&Thing::value)); //selects methods of kind void Y::zzz(X)
}
However, getters normally are const methods, so as_getter
might also want to deal with that.
Also, if possible, avoid needless overloading, particularly if you want to work with function pointers. IMO, a getter and a setter do sufficiently different things to deserve a different name.
精彩评论