0

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;
}
2
  • 1
    foo is a template. You call it in a way that requires argument deduction. There can be no conversion. Commented Jul 11, 2017 at 5:39
  • @StoryTeller What do I need to make it right Commented Jul 11, 2017 at 5:41

2 Answers 2

4

There are two major problems in your posted code.

  1. 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.

  2. 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>()));
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much. To my understanding, if I overload an operator of A, then there's no trivial way to use it for B. Because the compiler cannot deduce the type. Is it right? (you could see my edit)
@zhangwfjh Your edit does not change the problem you are facing. For template parameter deduction, the compiler won't perform any user defined conversions. That's the main problem.
0

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.

3 Comments

That won't help one iota. Template argument deduction will fail just the same. ideone.com/QoLDZ8
What is that copy constructor that takes a const reference of a B object?
@MarwanB I'm referring to A(const B<T>& b)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.