c – 使用PIMPL习语时有没有办法限制重复的样板?

我有类似以下内容
// foo.h:
class foo {
public:
    foo(); 
    ~foo();
    // note: the param type repetition here is only incidental,assume the
    // functions can't easily be made to share type signatures
    void bar(a b,c d);               
    void baz(a b,c d,e f,g h,i j);
    void quux(a b,i j);
private:
    class impl;
    impl *m_pimpl;
}

然后:

// foo.cpp:
class foo::impl {
public:
    void bar(a b,c d);
    void baz(a b,i j);

private:
    // lots of private state,helper functions,etc. 
};

void foo::impl::bar(a b,c d) { ... }
void foo::impl::baz(a b,i j) { ... }
void foo::impl::quux(a b,i j) { ... }

foo::foo() : m_pimpl(new impl()) { }
foo::~foo() { delete m_pimpl; m_pimpl = NULL; }
void foo::bar(a b,c d) {
    return m_pimpl->bar(b,d);
}
void foo::baz(a b,i j) {
    return m_pimpl->baz(b,d,f,h,j)
}
void foo::quux(a b,i j) {
    return m_pimpl->quux(b,j);
}

这里有很多重复的bar,baz和quux:

>一旦进入foo的声明
>一旦进入foo :: impl的声明
>一旦进入foo :: impl的定义
> foo定义中的两次:一次用于foo的函数参数列表,再次调用相应的foo :: impl函数.

对于除了最后一个之外的每一个我必须写出整个参数列表,其类型可以更多地涉及.

如果有的话,减少重复的最佳方法是什么?一个简单的方法是内联foo :: impl公共函数的定义,但是除了设计类以外的任何东西以外还有更少的公共函数吗?

解决方法

使用签名,我们可以将其减少到3个提及,加上1组前锋:
using signature_1 = int(int);

struct foo {
  signature_1 x;
  foo();
  ~foo();
private:
  struct fooimpl;
  std::unique_ptr<fooimpl> pimpl;
};

int main() {
  foo f;
  std::cout << f.x(1) << '\n';
}
struct foo::fooimpl {
  signature_1 x;
  int v = 3;
};

foo::~foo() = default;
foo::foo():pimpl(new foo::fooimpl()){}

int foo::x(int y){return pimpl->x(y);}
int foo::fooimpl::x(int y){return y+v;}

如果我们的pimpl是纯虚拟类,我们可以将它降低到2.从decltype(& foo :: method) – >签名写一个映射,并让纯虚拟接口使用该(和decltype)来创建纯虚拟类的签名.

在foo中写入一次签名,decltype-在foo_impl_interface中确定它,然后在cpp文件中的foo_impl内实现它.再加上一组前锋.

template<class MethodPtrType>
 struct method_sig;
 template<class MethodPtrType>
 using method_sig_t = typename method_sig<MethodPtrType>::type;
 template<class T,class R,class...Args>
 struct method_sig< R(T::*)(Args...) > {
   using type=R(Args...);
 };

加上另外11个奇数专长(叹气)来获得所有案例. (据我所知,const& const const&& const volatile const volatile& const volatile&&&&& volatile volatile&&&& qualifiers都是必需的).

现在method_sig_t< decltype(& foo :: x)>是int(int),我们可以使用:

struct foo_impl_interface {
  virtual method_sig_t<decltype(&foo::x)> x = 0;
  virtual ~foo_impl_interface() {}
};

假设我们使用pimpl来规范我们的类型而不是隐藏状态.

最后,不是在pimpl中实现大部分代码,而只是在pimpl中存储STATE,将代码保留在类本身中.

这给你“其他人不依赖于我的大小”:谁关心代码是在foo还是foo_impl中读取foo_impl的状态?那么如果你没有做foo_impl_interface技术,为什么要转发呢?

相关文章

对象的传值与返回说起函数,就不免要谈谈函数的参数和返回值...
从实现装饰者模式中思考C++指针和引用的选择最近在看...
关于vtordisp知多少?我相信不少人看到这篇文章,多半是来自...
那些陌生的C++关键字学过程序语言的人相信对关键字并...
命令行下的树形打印最近在处理代码分析问题时,需要将代码的...
虚函数与虚继承寻踪封装、继承、多态是面向对象语言的三大特...