用户定义的转换运算符将忽略类模板(对于非模板则不是)

时间:2018-07-17 11:40:46

标签: c++ c++11 templates implicit-conversion template-deduction

此代码确实可以编译(重要的一点是F()仅接受A,并且由于存在从BA的隐式转换,因此我可以轻松地将B传递给它。)

struct A {};

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

void F (A a) {}

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

但是模板版本无法编译:

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;
}

在GCC上出现以下错误(在MSVC上等效):

  

错误:没有匹配的函数可以调用“ F(B )”

(还有其他信息,即有F(A<>),但B并不继承自A。)

为了记录,在A中实现隐式转换运算符也无济于事。

为什么模板版本不编译?我想念什么吗?还是实际上没有办法使用类模板呢?!

(注意:我知道我可以在呼叫站点将B强制转换为A;这不是我喜欢的。)

2 个答案:

答案 0 :(得分:3)

Template argument deduction不考虑隐式转换。

  

类型推导不考虑隐式转换(上面列出的类型调整除外):这是超载解析的工作,稍后会发生。

必须首先推导模板参数<section>(在重载解析之前),但是给定参数<span>的参数T,则不能推导A<T>他们;然后编译失败。

作为解决方法,您可以按照说明使用显式转换,也可以显式指定模板参数。

B<int>

答案 1 :(得分:3)

正如Songyuanyao更好地解释的那样,必须在之前推导模板参数T

您可以解决重复T类型的问题

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

但我知道这很烦人。

因此,作为解决您问题的方法,我提出了另一个模板函数,该模板函数在调用T之前推导F()

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

因此您可以通过F()来呼叫G(),而不必重复T类型

G(B<int>{});
相关问题