【问题标题】:How can I offload dependency injected template class providing templated functions to pimpl class如何将提供模板化函数的依赖注入模板类卸载到 pimpl 类
【发布时间】:2022-11-01 14:55:31
【问题描述】:
我有一个应用程序类,它可以将依赖类作为构造函数的模板参数。这个依赖类需要提供应用程序类可以调用的某些模板化函数。我想将此依赖类对象卸载到 pimpl 类,因此应用程序类不是模板类,因此仅是标头。
这是我的意思的粗略概念。
///////////
// impl.h
///////////
struct Impl
{
public:
Impl(Helper& helper) : helper_(helper)
{
}
template <typename T>
void someHelperFn1(T t)
{
helper_->fn1(t);
}
template <typename U>
SomeOtherClass<U> someHelperFn2()
{
return helper_->fn2();
}
private:
Helper& helper_;
};
///////////
// app.h
///////////
#include "impl.h"
class App
{
public:
template<typename Helper>
App(Helper &h) :impl_(new Impl) {}
template <typename T>
void someHelperFn1(T t)
{
impl_->someHelperFn1(t);
}
template <typename U>
SomeOtherClass<U> someHelperFn2()
{
return impl_->someHelperFn2();
}
void someAppFn();
private;
std::unique_ptr<Impl> impl_;
};
///////////
// app.cpp
///////////
void App::someAppFn()
{
// some useful code
}
我意识到上面的代码无法编译,因为 Impl 实际上是一个模板类,所以 App 也将是一个模板类。这就是我想避免的,这样 App 就不是一个只有标题的类。我发现了一些东西similar,除了我想从辅助依赖项调用的函数是模板函数,在这种情况下它们不是。这似乎与我想做的非常接近。
关于如何避免使 App 成为模板类的任何想法?
我尝试让帮助类使用一个通用的基类,但这对于模板函数来说是不可能的。
【问题讨论】:
标签:
c++
templates
function-templates
pimpl-idiom
【解决方案1】:
您需要确保公共头文件(具有 pimpl 指针的类的那个)不会只公开头文件的实现的类模板。使用这样的接口
#include <memory>
#include <iostream>
// public header file
// for pimpl pattern I often use an interface
// (also useful for unit testing later)
class PublicItf
{
public:
virtual void do_something() = 0;
virtual ~PublicItf() = default;
protected:
PublicItf() = default;
};
// the public class implements this interface
// and the pimpl pointer points to the same interface
// added advantage you will have compile time checking that
// the impl class will all the methods too.
class PublicClass final :
public PublicItf
{
public:
PublicClass();
virtual ~PublicClass() = default;
void do_something() override;
private:
std::unique_ptr<PublicItf> m_pimpl; // the interface decouples from the template implementation (header file only)
};
// private header file
// this can now be a template
template<typename type_t>
class ImplClass final :
public PublicItf
{
public:
void do_something() override
{
m_value++;
std::cout << m_value << "
";
}
private:
type_t m_value{};
};
// C++ file for Public class
// inlcude public header and impl header (template)
PublicClass::PublicClass() :
m_pimpl{ std::make_unique<ImplClass<int>>() }
{
};
void PublicClass::do_something()
{
m_pimpl->do_something();
}
// main C++ file
int main()
{
PublicClass obj;
obj.do_something();
return 0;
}