Patrick Fromberg
Patrick Fromberg

Reputation: 1397

C++ Forward declaration before class or before member in the Pimple idiom?

Most Pimpl examples look as follows:

UPDATE: both cases fail, i.e. with and without namespaces. See answer from R Sahu at https://stackoverflow.com/a/57103016/2712726 . class Impl must be qualified with class name Simpl

// Simple.h
#include <memory>
class Simple {
     struct Impl; // WORKS!
     std::unique_ptr<Impl> impl_;
     public:
     Simple();
     ~Simple();
     int get() const;
};

But this seems to fail in the real world where you would use namespaces. When namespaces are present, then the forward declaration has to be moved before the class declaration. Can anyone explain why?

// Simple.h but now with name spaces
namespace weired::example {
    struct Impl; // OK! forwad declaration must go here
    class Simple {
         //struct Impl; // ERROR! incomplete type in ctor definition
         std::unique_ptr<Impl> impl_;
         public:
         Simple();
         ~Simple();
         int get() const;
    };
}

I have tested this with gcc9 and clang8 with -std=c++11 up to c++2a. Just for completeness, here are the Simple.cpp and main.cpp files so you can run the example yourself:

// Simple.cpp
#include "Simple.h"
namespace weired::example {

    struct Impl {int a,b;};

    Simple::Simple() : impl_(new Impl{3,4}) {}       

    Simple::~Simple() = default;

    int Simple::get() const
    {
        return impl_->a;
    }
}

and

// main.cpp
#include "Simple.h"
#include <iostream>

int main () {       
        auto nonsense = weired::example::Simple{};
        std::cout << nonsense.get() << '\n';
}   

Upvotes: 2

Views: 438

Answers (1)

R Sahu
R Sahu

Reputation: 206577

You may forward declare Impl inside the class and outside the class, regardless of whether Simple is defined in a namespace or globally.

The implementation of Impl is almost identical in both cases.

Without namespace

Option 1 (Impl is a peer class)

The .h file

struct Impl;
class Simple { ... };

The .cpp file

// Define Impl
struct Impl { ... };

// Define Simple

Option 2 (Impl is a nested class)

The .h file

class Simple
{
   struct Impl;
   ...
};

The .cpp file

// Define Impl
struct Simple::Impl { ... };  // Need the Simple:: scope here.

// Define Simple

With namespace

Option 1 (Impl is a peer class)

The .h file

namespace weired::example {

   struct Impl;
   class Simple { ... };
}

The .cpp file

namespace weired::example {

   // Define Impl
   struct Impl { ... };

   // Define Simple
}

Option 2 (Impl is a nested class)

The .h file

namespace weired::example {

   class Simple
   {
      struct Impl;
      ...
   };
}

The .cpp file

namespace weired::example {

   // Define Impl
   struct Simple::Impl { ... };  // Need the Simple:: scope here.

   // Define Simple
}

Upvotes: 2

Related Questions