开发者

Implicit casting in templates and compiler coercion

开发者 https://www.devze.com 2023-02-10 13:56 出处:网络
I have this very simple wrapper template: template<class T> struct wrapper { inline operator T () {

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消