无法解析模板委托中的重载类方法

时间:2010-10-15 23:56:52

标签: c++ templates function-pointers linker-errors overloading

背景:我正在使用委托技术来抽象对任意对象方法的访问,但是我遇到了一些涉及链接器的问题。考虑以下课程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);
};

Datum的实施无关紧要。还要考虑一下琐碎的班级Thing

class Thing {
  public:
    Thing(void);
    ~Thing(void);

    int   getValue(void)         { return _value; }
    void  setValue(const int& x) { _value = x; }
  private:
    int _value;
};

问题:我可以像这样构建ContextNode的实例化。

Thing* thing = new Thing();
ContextNode<Thing,int,int>* cn = new ContextNode<Thing,int,int>(thing, &Thing::getValue, &Thing::setValue);

这适合我的需要。我遇到问题,重载方法。假设我写了:

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);

无法链接。我相信这个问题是链接器只尝试基于名称的解析,因此我看到<unresolved overloaded function type>错误。

我的问题:是否有一些语法糖可以明确指定我所指的几个重载方法中的哪一个?我无法想象这样一个愚蠢的怪癖会破坏这样一个优雅的解决方案。我在网上找不到任何内容,也没有在C ++常见问题解答中找到任何内容,也没有找到关于该主题的SO。

解决了什么问题,或者我是否已经开始使用?

2 个答案:

答案 0 :(得分:2)

您可以使用强制转换来消除重载函数名称的歧义:

(int (Thing::*)(void))(&Thing::value)
(void (Thing::*)(const int&))(&Thing::value)

答案 1 :(得分:1)

也可以提供选择一个或另一个重载的实用程序函数。

//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)
}

但是,getter通常是const方法,因此as_getter也可能想要处理它。

另外,如果可能的话,避免不必要的重载,特别是如果你想使用函数指针。 IMO,一个吸气剂和一个二传手做了不同的事情,值得一个不同的名字。