[英]C++ non-member functions for nested template classes
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. 我认为这是相当典型的,比较是通过非成员(和非朋友)
operator==
函数执行的。 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. 这样做时,我的编译器(我正在使用带有
-O3 -g -Wall
标志的Mingw32 GCC 4.4)找不到该函数,并且我已经用尽了所有可能的原因。
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. 在下面的相当大的代码块中,有三个类:基类,保存基类的Composed类和与Composed类相同的Nested类,只不过它嵌套在Outer类中。 Non-member
operator==
functions are supplied for each. 每个成员都提供非成员
operator==
函数。 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. 在
main
,比较每个类的两个相同的对象。 For the untemplated case there is no problem, but for the templated case the compiler fails to find operator==
. 对于非模板情况,没有问题,但是对于模板情况,编译器无法找到
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;
}
The issue is fairly common with nested class with templates. 对于带有模板的嵌套类,该问题相当普遍。
template <class T>
struct Outer { struct Inner {}; };
template <class T>
void increment(typename Outer<T>::Inner&) {}
The increment
function cannot be found. 找不到
increment
功能。 I think the look up is too difficult for the compiler to solve. 我认为查找对于编译器来说太难了。
You can alleviate the problem though, 您可以缓解问题,
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
}
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. 根据经验,自由方法的参数(不适用于结果类型)中的
typename
是一个红色鲱鱼,似乎阻止了自动推论。
If you haven't overloaded operator&, then just compare memory addresses. 如果您还没有重载operator&,那么只需比较内存地址即可。 There's no need to do this.
不需要这样做。
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. 有了关于问题的更清晰的思路,我从C ++ FAQ中获得了新的启发,并将非成员
operator==
合并为类的友好函数。 This isn't as much of a hack as it sounds, since the reason for supplying an equal()
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. 这听起来不像是一个hack,因为提供
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) {}
};
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.