我们有一个客户希望访问的高度模板化的仅 header 代码库。例如,假设它包含 Foo
标题中的类 foo.hpp
:
#ifndef FOO_HEADER
#define FOO_HEADER
#include <iostream>
template <typename T>
struct Foo {
Foo(){
// Do a bunch of expensive initialization
}
void bar(T t){
std::cout << t;
}
// Members to initialize go here...
};
#endif /* FOO_HEADER */
现在我们想让客户在不暴露核心代码和不重写整个代码库的情况下尝试一组精简的功能。
一个想法是使用 PIMPL 习惯用法来包装这个核心代码。具体来说,我们可以创建一个 FooWrapper
标题为 foo_wrapper.hpp
的类:
#ifndef FOO_WRAPPER_HEADER
#define FOO_WRAPPER_HEADER
#include <memory>
struct FooWrapper {
FooWrapper();
~FooWrapper();
void bar(double t);
private:
struct Impl;
std::unique_ptr<Impl> impl;
};
#endif /* FOO_WRAPPER_HEADER */
和实现foo_wrapper.cpp
:
#include "foo.hpp"
#include "foo_wrapper.hpp"
struct FooWrapper::Impl {
Foo<double> genie;
};
void FooWrapper::bar(double t){
impl->genie.bar(t);
}
FooWrapper::FooWrapper() : impl(new Impl){
}
FooWrapper::~FooWrapper() = default;
这段代码如我所料:https://wandbox.org/permlink/gso7mbe0UEOOPG7j
然而,有一件小事困扰着我。具体来说,实现需要额外的间接级别......我们必须定义 Impl
类持有 Foo
的成员类(class)。因此,所有操作都具有 impl->genie.bar(t);
形式的间接寻址。 .
如果我们能以某种方式告诉编译器,“实际上 Impl
是类 Foo<double>
”会更好,在这种情况下,我们可以改为说 impl->bar(t);
.
具体来说,我在想一些类似 typedef
的事情或 using
让这个工作。有点像
using FooWrapper::Impl = Foo<double>;
但这不编译。那么问题来了:
- 是否有摆脱这种间接寻址的好方法?
- 我应该使用更好的成语吗?
我的目标是 C++11 解决方案,但 C++14 也可以。要记住的重要一点是解决方案不能使用标题 foo.hpp
在foo_wrapper.hpp
.我们必须以某种方式将该代码编译成一个库,并仅分发编译后的库和 foo_wrapper
标题。
最佳答案
您可以在 FooWrapper.h
中前向声明 Foo
。这将允许您为其声明一个 std::unique_ptr
:
#ifndef FOO_WRAPPER_HEADER
#define FOO_WRAPPER_HEADER
#include <memory>
// Forward declaration
template <typename T>
class Foo;
struct FooWrapper {
FooWrapper();
~FooWrapper();
void bar(double t);
private:
std::unique_ptr<Foo<double>> impl;
};
#endif /* FOO_WRAPPER_HEADER */
foo_wrapper.cc
:
#include "foo_wrapper.h"
#include "foo.h"
void FooWrapper::bar(double t) {
impl->bar(t);
}
FooWrapper::FooWrapper() : impl(std::make_unique<Foo<double>>()) {}
FooWrapper::~FooWrapper() = default;
关于C++ Pimpl Idiom 使用预先存在的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55593809/