Reputation: 123
I have a class A in which most operations are implemented. Also, I have another class B which contains only a member of A. And I wish operations in A can be directly applied to B. So I define a conversion operation. But the compiler complains "error: no matching function for call to 'foo'". What's wrong with implicit conversion and how to implement this? Thanks.
Edit: What if I add an operator overloading to A and want B to use it directly?
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;
}
Upvotes: 0
Views: 134
Reputation: 206567
There are two major problems in your posted code.
The compiler does not convert B<int>
to A<int>
to deduce the template parameters for foo
to be int
. You'll have to help the compiler. Use:
foo<int>(B<int>());
or
foo(static_cast<A<int>>(B<int>()));
That will solve only half the problem.
The conversion function, no matter which one is used by the compiler, results in a temporary object. A temporary object cannot bind to a A<int>&
. You'll have to use
template <typename T> void foo(A<T>) {}
or
template <typename T> void foo(A<T> const&) {}
Also, the friend
declaration in A
is not right. It declares a non-template function foo
to be the friend
of A<T>
. If you want foo<T>
to be a friend
of A<T>
, you'll have to change your code a little bit.
// 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);
};
Here's a complete program that builds successfully for me.
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>()));
}
Upvotes: 4
Reputation: 595711
foo()
takes a non-const reference as input. B
's conversion operator returns a temporary A
object, and a temp cannot be bound to a non-const reference parameter. That is why your call to foo()
fails to compile.
If you were to change the input parameter to take a const reference instead, it can bind to a temp object. But, A
has a copy constructor that takes a const reference to a B
object as input, so your call to foo()
might still be ambiguous. After constructing the temp B
object, should the compiler call the A
copy constructor with the B
as input, or should it call the B
conversion operator that returns an A
? I'm not sure what the standard says about that, or how compilers implement that.
Upvotes: 0