代码之家  ›  专栏  ›  技术社区  ›  Chris Tonkinson

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

  •  1
  • Chris Tonkinson  · 技术社区  · 14 年前

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

    问题: 我可以构造 上下文节点 像这样。

    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++ FAQ上找到,也不在这里。

    是怎么解决的,还是我被冲洗了?

    2 回复  |  直到 14 年前
        1
  •  2
  •   James McNellis    14 年前

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

    (int (Thing::*)(void))(&Thing::value)
    (void (Thing::*)(const int&))(&Thing::value)
    
        2
  •  1
  •   UncleBens    14 年前

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

    //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 可能还想解决这个问题。

    另外,如果可能的话,避免不必要的重载,特别是当您想使用函数指针时。在我看来,一个能手和一个二传手做的事情完全不同,应该有一个不同的名字。