The following code, in which the Info nested class designates two member functions of the Impl outer class as friends, compiles well with Visual C ++ and g ++, with the code below.
But if member functions are not declared before Info , then g ++ complains about the incomplete class, and not about the lack of declaration:
In file included from ../console_io.hpp:6:07,
from console_io.cpp: 1:
../console_io.impl.windows.hpp:69:47: error: invalid use of incomplete type 'class console :: Display :: Impl'
friend auto Impl :: api_info () const -> Ref_ <const Api_info>;
^
../console_io.impl.windows.hpp:62:20: note: definition of 'class console :: Display :: Impl' is not complete until the closing brace
class Display :: Impl
^
../console_io.impl.windows.hpp:70:47: error: invalid use of incomplete type 'class console :: Display :: Impl'
Minimal example:
struct Foo { class Bar { friend void Foo::m(); }; void m(){} };
foo.cpp: 5: 28: error: invalid use of incomplete type 'struct Foo'
friend void Foo :: m ();
^
foo.cpp: 1: 8: note: definition of 'struct Foo' is not complete until the closing brace
struct foo
^
So, by association, I am interested in the formal reliability of creating a member function T a friend , at the point where T is not yet complete.
I present the actual source code that is compiling, so that if it is formally invalid, reasonable alternatives for this use case can be suggested. I think that I, as one who asks, is perhaps the least competent to decide what is important or not for the answers. Designation: Ref_<T> means T& .
class Display::Impl { private: using Api_info = impl::winapi::Console_screen_buffer_info; inline auto api_info() const -> Ref_<const Api_info>; // Def. after class. inline void invalidate_api_info(); // Def. after class. class Info { friend auto Impl::api_info() const -> Ref_<const Api_info>; friend void Impl::invalidate_api_info(); private: bool is_valid_ = false; Api_info api_info_ = {}; }; // State: impl::winapi::Handle text_buffer_; mutable Info info_; Impl( Ref_<const Impl> ) = delete; auto operator=( Ref_<const Impl> ) -> Ref_<Impl> = delete; public: auto size() const -> Point { auto const api_size = api_info().dwSize; return Point{ api_size.x, api_size.y }; } ~Impl() {} // TODO: Impl( const Point size ) : text_buffer_( impl::winapi::CreateConsoleScreenBuffer( impl::winapi::flag_GENERIC_READ | impl::winapi::flag_GENERIC_WRITE, 0, // No sharing nullptr, // Default security. impl::winapi::flag_CONSOLE_TEXTMODE_BUFFER, // The allowed value. nullptr // Reserved. ) ) { hopefully( text_buffer_ != impl::winapi::invalid_handle_value ) || fail( "console::Display: CreateConsoleScreenBuffer failed" ); } }; auto Display::Impl::api_info() const -> Ref_<const Api_info> { if( not info_.is_valid_ ) { impl::winapi::GetConsoleScreenBufferInfo( text_buffer_, &info_.api_info_ ) || fail( "GetConsoleScreenBufferInfo failed" ); info_.is_valid_ = true; } return info_.api_info_; } void Display::Impl::invalidate_api_info() { info_.is_valid_ = false; }
c ++ friend friend-function
Cheers and hth. - alf
source share