C++嵌套模板类的非成员函数
我一直在编写几个包含嵌套迭代器类的类模板,需要进行相等比较。正如我认为相当典型的那样,比较是使用非成员(和非友元)operator==
函数执行的。这样做时,我的编译器(我使用带有标志 -O3 -g -Wall
的 Mingw32 GCC 4.4)无法找到该函数,并且我已经排除了可能的原因。
在下面相当大的代码块中,有三个类:一个基类、一个包含基类对象的组合类,以及一个与组合类相同的嵌套类,只不过它嵌套在外部类中。为每个函数提供非成员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;
}
I have been writing several class templates that contain nested iterator classes, for which an equality comparison is required. As I believe is fairly typical, the comparison is performed with a non-member (and non-friend) operator==
function. In doing so, my compiler (I'm using Mingw32 GCC 4.4 with flags -O3 -g -Wall
) fails to find the function and I have run out of possible reasons.
In the rather large block of code below there are three classes: a Base class, a Composed class that holds a Base object, and a Nested class identical to the Composed class except that it is nested within an Outer class. Non-member operator==
functions are supplied for each. These classes are in templated and untemplated forms (in their own respective namespaces), with the latter equivalent to the former specialised for unsigned integers.
In main
, two identical objects for each class are compared. For the untemplated case there is no problem, but for the templated case the compiler fails to find operator==
. What's going on?
#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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这个问题对于带有模板的嵌套类来说相当常见。
找不到
increment
函数。我认为查找对于编译器来说太难解决。不过你可以缓解这个问题,
有趣,不是吗?
根据经验,自由方法的参数(不适用于结果类型)中的
typename
是一种转移注意力的方法,并且似乎会阻止自动参数推导。The issue is fairly common with nested class with templates.
The
increment
function cannot be found. I think the look up is too difficult for the compiler to solve.You can alleviate the problem though,
Funny, isn't it ?
As a rule of thumb,
typename
in the arguments (not for the result type) of a free method is a red herring and seems to prevent automatic argument deduction.接受答案后,我思考如何以最小的努力最好地修复我的代码。有了对问题更清晰的认识,我从 中获得了新的灵感C++ FAQ 并将非成员
operator==
作为友元函数合并到类定义中。这并不像听起来那么麻烦,因为提供 equal() 成员函数的原因是为了避免需要友元,但对于模板来说,友元函数的好处是允许函数定义保存在类体内,从而避免查找问题。After accepting an answer, I thought about how best to fix my code with the minimum effort. Armed with a clearer idea of the problem I took new inspiration from the C++ FAQ and merged the non-member
operator==
into the class definition as a friend function. This isn't as much of a hack as it sounds, since the reason for supplying anequal()
member function was to avoid the need of a friend, but for templates a friend function has the benefit of allowing the function definition to be held within the class body, thus avoiding the lookup issues.如果您没有重载operator&,那么只需比较内存地址即可。没有必要这样做。
If you haven't overloaded operator&, then just compare memory addresses. There's no need to do this.