I have this very simple wrapper template:
template<class T>
struct wrapper {
inline operator T () {
return v;
}
inline wrapper(T v):v(v) { }
T v;
};
Trying to use it with any non-primitive type with (for example) comparison operator relying on the template having it defined doesn't look promising:
std::string t = "test";
assert(t == t);
typedef wrapper<std::string> string_wrapp开发者_Python百科er;
assert(string_wrapper(t) == string_wrapper(t));
GCC 4.4.5 complains with this error:
error: no match for ‘operator==’ in ‘wrapper<std::basic_string<char> >(std::basic_string<char>(((const std::basic_string<char>&)((const std::basic_string<char>*)(& t))))) == wrapper<std::basic_string<char> >(std::basic_string<char>(((const std::basic_string<char>&)((const std::basic_string<char>*)(& t)))))’
What is interesting is that GCC triple-casts the template then fails to use operator ==
that was defined for std::string
.
I don't think that implicit coercion is impossible, since if I change std::string
to int
or double
, bool
or anything primitive, GCC will choose the correct operator.
I do not want to define operator ==
for the wrapper struct, because that operator is just an example, and I need wrapper
to 'feel' just like the real type regarding operators.
Just in cast GCC misunderstands my syntax, if I create a wrapper and try to compare it to itself, GCC complains again (though without triple casting) that it cannot find a matching == operator:
typedef wrapper<std::string> string_wrapper;
string_wrapper tw(t);
assert(tw == tw);
error: no match for ‘operator==’ in ‘tw == tw’
Why can't GCC find and/or use std::string operator == std::string
when wrapper
provides the cast?
That operator T is called a "conversion operator" or "conversion function" instead of a cast. "Conversions" are implicit; casting is explicit.
The compiler can't find the operator== for std::string because the overload resolution rules don't allow that to happen. More details about what you're really trying to do could help provide a solution.
Apparently this is a GCC 4.5 bug. The code is valid, unlike what Fred Nurk says.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45383
The questioner has answered itself with some GCC PR, but which really does not answer his question.
The reason is like @Fred describes. Reducing it:
template<typename T>
struct A {
operator T() { return T(); }
};
int main() {
A<std::string>() == A<std::string>();
}
What can the compiler do? It could call operator std::string()
on both operands and then do the comparison. But why should it do that call in the first place? It first needs to find an operator==
that has two parameters of type std::string
. Let's look at how its operator is defined
template<class charT, class traits, class Allocator>
bool operator==(const basic_string<charT,traits,Allocator>& lhs,
const basic_string<charT,traits,Allocator>& rhs);
There we have it. It first needs to do template argument deduction, and the fact that A
does not match const basic_string<>
will make it so that this operator==
is ignored. You are lucky that operator==
is found anyway using ADL so that it does argument deduction in the first place (since std::string
is a template argument of your type, it will consider namespace std
by ADL and find this operator).
So we have no suitable operator==
to call and therefor GCC is alright with rejecting your code for the reasons @Fred gave in a nutshell. In the end, trying to make a class behave like another type is deemed to failure.
精彩评论