templates and casting operators
This code compiles in CodeGear 2009 and Visual Studio 2010 but not gcc. Why?
class Foo
{
public:
operator int() const;
template <typename T> T get() const { return this->operator T(); }
};
Foo::operator int() const
{
return 5;
}
The error message is:
test.cpp: In member function `T Foo::get() const':
test.cpp:6: error: 'const class Foo' has no member 开发者_运维问答named 'operator T'It's a bug in G++. operator T
is an unqualified dependent name (because it has T
in it and lookup will thus be different depending on its type). As such it has to be looked up when instantiating. The Standard rules
Two names are the same if
- ...
- they are the names of user-defined conversion functions formed with the same type.
Thus the type name specified after the operator keyword doesn't have to match lexically in any way. You can apply the following work-around to force GCC treating it as a dependent name
template<typename T, typename>
struct identity { typedef T type; };
class Foo
{
public:
operator int() const;
template <typename T> T get() const {
return this->identity<Foo, T>::type::operator T();
}
};
I'm not sure what the exact rules for the names of C++ operators are, but I believe it's trying to call operator T()
instead of operator int()
. Why not just use a cast:
template <typename T> T get() const { return static_cast<T>(*this); }
I haven't tested this but I believe this will accomplish more or less the same thing. If not, there should be a way to accomplish this without having to call operator T()
directly. That's what overloaded operators are for, after all.
If I modify the code slightly to this:
template <typename T> T get() const { return operator T(); }
I get the following with GCC:
there are no arguments to 'operator T' that depend on a template parameter, so a declaration of 'operator T' must be available (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)
But if you were to use -fpermissive, the whole thing would only work if T = int
On the other hand, why not do:
template <typename T> T get() const { return *this; }
That's sort of the point of the conversion operator.
I'm s bit curious about the use case for this. I suppose it is so you can say:
Foo f;
int x = f.get<int>();
but why not say:
Foo f;
int x = static_cast<int>(f);
which is slightly longer to type (though one could use the C cast notation), but doesn't need any hoop jumping.
精彩评论