C ++是否在Pimple习语中的类之前或成员之前声明声明?

时间:2019-07-18 21:25:28

标签: c++ namespaces forward-declaration pimpl-idiom incomplete-type

大多数 Pimpl 示例如下:

更新:两种情况均失败,即使用和不使用命名空间。请参阅https://stackoverflow.com/a/57103016/2712726中R Sahu的回答。 Impl类必须使用类名Simpl

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

但是,在使用命名空间的现实世界中,这似乎失败了。 如果存在名称空间,则必须将前向声明移到类声明之前。谁能解释为什么?

// 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;
    };
}

我已经使用gcc9clang8以及-std=c++11c++2a对此进行了测试。 为了完整起见,这里有Simple.cpp和main.cpp文件,因此您可以自己运行示例:

// 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;
    }
}

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

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

1 个答案:

答案 0 :(得分:2)

无论Impl是在命名空间中定义还是在全局中定义,您都可以在类内部和类外部转发声明Simple

在两种情况下,Impl的实现几乎相同。

没有namespace

选项1(Impl是对等类)

.h文件

struct Impl;
class Simple { ... };

.cpp文件

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

// Define Simple

选项2(Impl是嵌套类)

.h文件

class Simple
{
   struct Impl;
   ...
};

.cpp文件

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

// Define Simple

使用namespace

选项1(Impl是对等类)

.h文件

namespace weired::example {

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

.cpp文件

namespace weired::example {

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

   // Define Simple
}

选项2(Impl是嵌套类)

.h文件

namespace weired::example {

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

.cpp文件

namespace weired::example {

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

   // Define Simple
}