3

我一直在编写几个包含嵌套迭代器类的类模板,需要对其进行相等比较。我认为这是相当典型的,比较是使用非成员(和非朋友)operator==函数执行的。这样做时,我的编译器(我正在使用带有 flags 的 Mingw32 GCC 4.4 -O3 -g -Wall)无法找到该函数,并且我已经用完了可能的原因。

在下面相当大的代码块中,有三个类:一个 Base 类、一个包含 Base 对象的 Composed 类和一个与 Composed 类相同的 Nested 类,只是它嵌套在 Outer 类中。operator==为每个提供非成员函数。这些类采用模板化和非模板化形式(在它们各自的命名空间中),后者相当于前者专门用于无符号整数。

main中,比较每个类的两个相同对象。对于未模板化的情况没有问题,但对于模板化的情况,编译器找不到operator==. 这是怎么回事?

#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;
}
4

3 回答 3

5

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

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在自由方法的参数(不是结果类型)中是一条红鲱鱼,似乎可以防止自动参数推导。

于 2010-05-21T12:58:23.680 回答
1

接受答案后,我考虑如何以最小的努力最好地修复我的代码。对问题有了更清晰的认识,我从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) {}
  };
};
于 2010-05-22T05:32:11.560 回答
-1

如果您没有重载运算符&,则只需比较内存地址。没有必要这样做。

于 2010-05-21T12:35:32.833 回答