简体   繁体   中英

User-Defined Conversion Operator Ignored for Class Template (Not So for Non-templates)

This code does compile (the important point is that F() only accepts A s, and since there is an implicit conversion from B to A , I can easily pass a B to it.)

struct A {};

struct B {
    constexpr operator A () const {return {};}
};

void F (A a) {}

int main() {
    F(B());
    return 0;
}

But the templated version does not compile:

template <typename T>
struct A {};

template <typename T>
struct B {
    constexpr operator A<T> () const {return {};}
};

template <typename T>
void F (A<T> a) {}

int main() {
    F(B<int>());
    return 0;
}

with the following error on GCC (and equivalent on MSVC):

error: no matching function for call to 'F(B<int>)'

(with additional info that there is an F(A<>) but B does not inherit from A .)

For the record, implementing an implicit conversion operator in A doesn't help either.

Why doesn't the template version compile? Am I missing something? Or there is actually no way to do it with class templates?!

(Note: I know that I can explicitly cast B to A at call site; this is not something I prefer.)

Template argument deduction doesn't consider implicit conversion.

Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.

The template parameter T must be deduced at first (before overload resolution), but given the parameter A<T> with argument B<int> , T can't be deduced from them; then compilation fails.

As the workaround, you can use explicit conversion as you said, or specify the template argument explicitly.

F<int>(B<int>());

As better explained by songyuanyao, the template parameter T must be deduced before.

You can solve the problem explicating the T type

F<int>(B<int>());

but I understand that can be annoying.

So, as workaround for your problem, I propose another template function that deduce T before calling F()

template <template <typename> class C, typename T>
void G (C<T> const & c)
 { F<T>(c); }

so you can call F() , passing through G() , without explicating the T type

G(B<int>{});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM