У нас есть сильно кодированная база кодов только для заголовков, к которой клиент хотел бы получить доступ. Например, предположим, что он содержит класс 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
. Из-за этого все операции имеют эту косвенную форму вида 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
.