Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why does the conversion operator need a definition of the class converted to?

Consider the following code:

// A.hpp
class B;
class A
{
public:
    B b();
    operator B(){return b();}
};


// B.hpp
class B{
};

// A.cpp
// would include B.hpp and A.hpp
B A::b(){
    return {};
}

// main.cpp
// would include A.hpp and B.hpp
int main()
{
    A a{};
    B b(a);
}

It does not compile:

files.cpp:7:17: error: return type ‘class B’ is incomplete
    7 |     operator B(){return b();}
      |                 ^
files.cpp: In member function ‘A::operator void()’:
files.cpp:7:26: error: invalid use of incomplete type ‘class B’
    7 |     operator B(){return b();}
      |                         ~^~
files.cpp:2:7: note: forward declaration of ‘class B’
    2 | class B;
      |       ^
files.cpp: In function ‘int main()’:
files.cpp:26:12: error: no matching function for call to ‘B::B(A)’
   26 |     B b(A{});
      |            ^
files.cpp:12:7: note: candidate: ‘constexpr B::B()’
   12 | class B{
      |       ^
files.cpp:12:7: note:   candidate expects 0 arguments, 1 provided
files.cpp:12:7: note: candidate: ‘constexpr B::B(const B&)’
files.cpp:12:7: note:   no known conversion for argument 1 from ‘A’ to ‘const B&’
files.cpp:12:7: note: candidate: ‘constexpr B::B(B&&)’
files.cpp:12:7: note:   no known conversion for argument 1 from ‘A’ to ‘B&&’

Why can’t the conversion operator A::operator B() delegate to A::b() without B being defined?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

 operator B(){return b();}

The compiler must compile b(). To do this, the compiler needs to know what the mysterious B class is all about. The simple reason for this is because the C++ standard requires this. There’s always a single reason for why anything has to be in some particular way, in C++: it’s required by the standard.

As far as practical reasons go, there can be many. For example, on some implementations objects that get returned from a function that are small enough may be returned in a specific CPU register. Bigger objects will require a different approach. The compiler must know what to do, in order to actually compile this return statement. That’s actual code. That’s not a declaration, that you can get away with, with a forward-declared type.

Your solution is very simple. Just declare the conversion operator:

 operator B();

Then, later in the code, after B is defined, and at the precise location where A::b gets defined, define A::operator B() in exactly the same way. Problem solved.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading