Function of a member of an incomplete class as a friend = formally valid?

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; } 
+2
c ++ friend friend-function
source share
2 answers

After a little digging, I think this is what you are looking for:

& sect; 9.3 [class.mfct]:

7 Previously declared member functions may be referred to in friend announcements.

So (as far as I understand the standard), your code is valid when you declare a member function in front of your nested class.

+1
source share

Here is an example that compiles fine even with gcc-4.7 from Debian 7:

 class B; class C { inline auto f() const -> B&; class In { friend auto C::f() const -> B&; int i; }; }; class B { int b; }; auto C::f() const -> B& { static B b; return b; }; 

Therefore, I assume that the problem is with nesting classes.

0
source share

All Articles