代码之家  ›  专栏  ›  技术社区  ›  beldaz Nicolas W.

嵌套模板类的C++非成员函数

  •  2
  • beldaz Nicolas W.  · 技术社区  · 15 年前

    我已经编写了几个包含嵌套迭代器类的类模板,需要对这些类进行相等比较。因为我认为这是相当典型的,所以比较的对象是非会员(和非朋友)。 operator== 功能。在执行此操作时,我的编译器(我使用带有标志的mingw32 gcc 4.4 -O3 -g -Wall )找不到这个函数,我已经没有可能的原因了。

    在下面相当大的代码块中,有三个类:基类、包含基对象的组合类和与组合类相同的嵌套类,只是嵌套在外部类中。非成员 运算符== 每个都有功能。这些类采用模板化和非模板化形式(在各自的名称空间中),后者相当于前者专门用于无符号整数。

    main ,比较每个类的两个相同对象。对于未模板化的情况没有问题,但是对于模板化的情况,编译器找不到 运算符== . 发生什么事?

    #include <iostream>
    
    namespace templated {
    
    template<typename T>
    class Base {
      T t_;
    public:
      explicit Base(const T& t) : t_(t) {}
    
      bool
      equal(const Base& x) const {
        return x.t_==t_;
      }
    };
    
    template<typename T>
    bool
    operator==(const Base<T> &x, const Base<T> &y) {
      return x.equal(y);
    }
    
    template<typename T>
    class Composed {
      typedef Base<T> Base_;
      Base_ base_;
    public:
      explicit Composed(const T& t) : base_(t) {}
      bool equal(const Composed& x) const {return x.base_==base_;}
    };
    
    template<typename T>
    bool
    operator==(const Composed<T> &x, const Composed<T> &y) {
      return x.equal(y);
    }
    
    template<typename T>
    class Outer {
    public:
      class Nested {
        typedef Base<T> Base_;
        Base_ base_;
      public:
        explicit Nested(const T& t) : base_(t) {}
        bool equal(const Nested& x) const {return x.base_==base_;}
      };
    };
    
    template<typename T>
    bool
    operator==(const typename Outer<T>::Nested &x,
        const typename Outer<T>::Nested &y) {
      return x.equal(y);
    }
    
    } // namespace templated
    
    namespace untemplated {
    
    class Base {
      unsigned int t_;
    public:
      explicit Base(const unsigned int& t) : t_(t) {}
    
      bool
      equal(const Base& x) const {
        return x.t_==t_;
      }
    };
    
    bool
    operator==(const Base &x, const Base &y) {
      return x.equal(y);
    }
    
    class Composed {
      typedef Base Base_;
      Base_ base_;
    public:
      explicit Composed(const unsigned int& t) : base_(t) {}
      bool equal(const Composed& x) const {return x.base_==base_;}
    };
    
    bool
    operator==(const Composed &x, const Composed &y) {
      return x.equal(y);
    }
    
    class Outer {
    public:
      class Nested {
        typedef Base Base_;
        Base_ base_;
      public:
        explicit Nested(const unsigned int& t) : base_(t) {}
        bool equal(const Nested& x) const {return x.base_==base_;}
      };
    };
    
    bool
    operator==(const Outer::Nested &x,
        const Outer::Nested &y) {
      return x.equal(y);
    }
    
    } // namespace untemplated
    
    int main() {
      using std::cout;
      unsigned int testVal=3;
      { // No templates first
        typedef untemplated::Base Base_t;
        Base_t a(testVal);
        Base_t b(testVal);
    
        cout << "a=b=" << testVal << "\n";
        cout << "a==b ? " << (a==b ? "TRUE" : "FALSE") << "\n";
    
        typedef untemplated::Composed Composed_t;
        Composed_t c(testVal);
        Composed_t d(testVal);
    
        cout << "c=d=" << testVal << "\n";
        cout << "c==d ? " << (c==d ? "TRUE" : "FALSE") << "\n";
    
        typedef untemplated::Outer::Nested Nested_t;
        Nested_t e(testVal);
        Nested_t f(testVal);
    
        cout << "e=f=" << testVal << "\n";
        cout << "e==f ? " << (e==f ? "TRUE" : "FALSE") << "\n";
      }
      { // Now with templates
        typedef templated::Base<unsigned int> Base_t;
        Base_t a(testVal);
        Base_t b(testVal);
    
        cout << "a=b=" << testVal << "\n";
        cout << "a==b ? " << (a==b ? "TRUE" : "FALSE") << "\n";
    
        typedef templated::Composed<unsigned int> Composed_t;
        Composed_t c(testVal);
        Composed_t d(testVal);
    
        cout << "c=d=" << testVal << "\n";
        cout << "d==c ? " << (c==d ? "TRUE" : "FALSE") << "\n";
    
        typedef templated::Outer<unsigned int>::Nested Nested_t;
        Nested_t e(testVal);
        Nested_t f(testVal);
    
        cout << "e=f=" << testVal << "\n";
        cout << "e==f ? " << (e==f ? "TRUE" : "FALSE") << "\n";
        // Above line causes compiler error:
        // error: no match for 'operator==' in 'e == f'
      }
    
      cout << std::endl;
      return 0;
    }
    
    3 回复  |  直到 15 年前
        1
  •  5
  •   Matthieu M.    15 年前

    这个问题在带有模板的嵌套类中相当常见。

    template <class T>
    struct Outer { struct Inner {}; };
    
    template <class T>
    void increment(typename Outer<T>::Inner&) {}
    

    这个 increment 找不到函数。我认为查找对于编译器来说太困难了。

    不过,你可以缓解这个问题,

    namespace detail
    {
      template <class T> struct InnerImpl {};
    
      template <class T> void increment(InnerImpl& ) {}
    }
    
    template <class T>
    struct Outer
    {
      typedef detail::InnerImpl<T> Inner;
    };
    
    int main(int argc, char* argv[])
    {
      Outer<int>::Inner inner;
      increment(inner);         // works
    }
    

    很有趣,不是吗?

    根据经验, typename 在自变量(不是结果类型)中,自由方法是一个红鲱鱼,似乎阻止了自变量的推导。

        2
  •  0
  •   Puppy    15 年前

    如果您没有重载操作符&,那么只需比较内存地址即可。没必要这么做。

        3
  •  0
  •   beldaz Nicolas W.    15 年前

    在接受了一个答案之后,我考虑了如何以最小的努力来修复我的代码。我对这个问题有了更清晰的认识,从 C++ FAQ 合并了非成员 operator== 将类定义作为友元函数。这不像听起来那么简单,因为提供 equal() 成员函数是为了避免朋友的需要,但是对于模板,朋友函数的好处是允许函数定义保留在类体中,从而避免查找问题。

    template<typename T>
    class Outer {
    public:
      class Nested {
        typedef Base<T> Base_;
        Base_ base_;
        friend bool operator==(Nested const &x, Nested const &y) {
          return x.base_==y.base_;
        }
      public:
        explicit Nested(const T& t) : base_(t) {}
      };
    };