Heya, folks. I'm porting some code from a project largely developed in MSVS to use g++. I've found a lot of little differences, mostly things that M开发者_如何学CSVS allows but g++ does not. Usually it's something involving c++ standards, things that MSVS lets slide, but I'm having trouble seeing just what's wrong with one particular section.
g++ is having trouble matching a call to operator !=, but only in a specific context. Looking up operator != for a particular nested class works if the hosting class is not a template. If I turn the hosting class into a class template, however, everything breaks. I'm either missing something fundamental to c++, or g++ is doing something wrong.
I've learned not to cry "Compiler Bug!" too often, so I wanted to see if anyone here can see what I'm missing.
This worked example shows the working, non-template version, and then the broken, template version. g++ --version gives: g++ (Ubuntu 4.4.1-4ubuntu9) 4.4.1
Working reference version without templates
namespace Works {
struct host {
struct iterator {};
iterator op();
};
bool operator != (host::iterator const& a0, host::iterator const& a1);
bool f() {
return host().op() != host().op();
}
} // namespace Works
Broken version with templates
namespace Broken {
template <typename T>
struct host {
struct iterator {};
iterator op();
};
template <typename T>
bool operator != (typename host<T>::iterator const& a0,
typename host<T>::iterator const& a1);
bool f() {
return host<int>().op() != host<int>().op();
}
} // namespace Broken
The template version fails with the errors:
Main.cpp: In function ‘bool Broken::f()’:
Main.cpp:50: error: no match for ‘operator!=’ in ‘Broken::host<int>().Broken::host<T>::op [with T = int]() != Broken::host<int>().Broken::host<T>::op [with T = int]()’
This works neither in msvc nor gcc.
The problem is that in host<T>::iterator
, T
is in non-deducible context. Since neither parameter allows T
to be deduced, the function template cannot be instantiated.
That's why you usually define overloaded operators inside the class.
struct iterator
{
friend bool operator != (iterator const & lhs, iterator const & rhs)
{
return false;
}
};
i hit a similar thing. C++ operator overloads are supposed to take const inputs. msvc will let you get away with using non const inputs. G++ insists they are const
Building an @avakar's answer, I got the code to work properly, though it's a little strange:
namespace Broken {
template <typename T> struct host;
template <typename T>
bool operator != (typename host<T>::iterator const& a0,
typename host<T>::iterator const& a1);
template <typename T>
struct host {
struct iterator {
friend bool operator !=(iterator const & lhs, iterator const & rhs) {
return operator !=<int>(lhs, rhs);
}
};
iterator op();
};
bool f() {
// The following does indeed end up calling the operator != you want it to call. I
// have a slightly different version in which I tested this.
return host<int>().op() != host<int>().op();
}
} // namespace Broken
This gets around the problem that the template arguments to the top level operator !=
cannot be deduced by calling it with an explicit template argument from a friend function. It requires forward declaring the host
template.
精彩评论