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?
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.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments