模板函数的隐式转换

Implicit conversion of template function

本文关键字:转换 函数      更新时间:2023-10-16

我有一个A类,其中实现了大多数操作。另外,我还有另一个 B 类,它只包含 A 的成员。我希望 A 中的操作可以直接应用于 B。所以我定义了一个转换操作。但是编译器抱怨"错误:没有匹配函数来调用'foo'"。隐式转换有什么问题以及如何实现这一点?谢谢。

编辑:如果我将运算符重载添加到 A 并希望 B 直接使用它怎么办?

template <typename T> struct B;
template <typename T>
struct A {
A(const B<T>& b) {}    // Conversion from B to A, way 1
friend void foo(const A&);
// Addition
friend A operator+(const A&, const A&);
};
template <typename T>
void foo(A<T>& a) {}
// Addition
template <typename T>
A<T> operator+(const A<T>& a1, const A<T>& a2) { return A<T>(); }
template <typename T>
struct B {
B() {}
A<T> a;
operator A<T>() { return a; }   // Conversion from B to A, way 2
// Addition
B(const A<T>& a) : a(a) {}
};
int main()
{
B<int> b;
foo(b);
auto bb = b+b;
}

您发布的代码中有两个主要问题。

  1. 编译器不会将B<int>转换为A<int>以推导出要intfoo的模板参数。你必须帮助编译器。用:

    foo<int>(B<int>());
    

    foo(static_cast<A<int>>(B<int>()));
    

    这只能解决一半的问题。

  2. 无论编译器使用哪一个,转换函数都会生成一个临时对象。临时对象无法绑定到A<int>&。你必须使用

    template <typename T> void foo(A<T>) {}
    

    template <typename T> void foo(A<T> const&) {}
    

此外,Afriend声明是不正确的。它声明了一个非模板函数fooA<T>friend。如果你想foo<T>成为A<T>friend,你必须稍微改变你的代码。

// Declare the class template A first.
template <typename T> class A;
// Declare the funtion template foo next.
template <typename T> void foo(A<T>);
// Declare foo<T> to be friend of A<T> in the definition of A.
template <typename T>
struct A {
...
friend void foo<>(A);
};

这是一个为我成功构建的完整程序。

template <typename T> struct B;
template <typename T> struct A;
template <typename T> void foo(A<T> a);
template <typename T>
struct A {
A(const B<T>& b) : x{b.a.x} {}    // Conversion from B to A, way 1
A(T x) : x{x} {}
T x;
friend void foo<>(A);
};
template <typename T>
void foo(A<T> a) {}
template <typename T>
struct B {
B() : a{0} {}
A<T> a;
// This is not necessary for conversion of B<T> to A<T>
// operator A<T>() { return a; }   // Conversion from B to A, way 2
};
int main()
{
foo<int>(B<int>());
foo(static_cast<A<int>>(B<int>()));
}

foo()将非常量引用作为输入。B的转换运算符返回一个临时A对象,并且 temp 不能绑定到非常量引用参数。这就是您对foo()调用无法编译的原因。

如果要更改输入参数以改为采用 const 引用,它可以绑定到 temp 对象。但是,A有一个复制构造函数,该构造函数将对B对象的 const 引用作为输入,因此对foo()的调用可能仍然不明确。 构造临时B对象后,编译器应该调用A复制构造函数,B作为输入,还是应该调用返回AB转换运算符? 我不确定标准对此有何规定,或者编译器如何实现这一点。