我正在解决一个相对简单的问题,但似乎无法找到解决这个问题的方法 - 甚至有点hackish ......,我只是陷入困境并且可以使用一些似乎不会出现的想法。下面显示的代码示例不是(完全)工作,而是显示我的问题。
我有一个控制器类,包含3个方法init
,process
和dispose
。 Controller基本上是一个或多个要执行的所谓组件的包装器。
此外,还有一个component_manager
类来创建组件实例并管理它们的生命周期。组件管理器派生自定义4个虚拟方法的接口,例如init
,prepare
,recycle
和dispose
。
组件本身也有一个定义良好的接口icomponent
。所有组件都派生自该接口,并且所有组件都是默认构造的(不需要参数)。
为了显示一些代码,我从我正在试验的代码中提取了重要的部分,而忽略了`controller'包装类及其周围的所有噪音。
namespace detail {
// Iterator for std::tuple
template<typename Tuple, typename F, std::size_t ...Indices>
constexpr void for_each_impl(Tuple&& tuple, F&& f, std::index_sequence<Indices...>)
{
using swallow = int[];
(void)swallow{1,
(f(std::get<Indices>(std::forward<Tuple>(tuple))), void(), int{})...
};
}
} // Namespace detail
template<typename Tuple, typename F>
constexpr void for_each(Tuple&& tuple, F&& f)
{
constexpr std::size_t N = std::tuple_size<std::remove_reference_t<Tuple>>::value;
detail::for_each_impl(std::forward<Tuple>(tuple), std::forward<F>(f),
std::make_index_sequence<N>{});
}
// A component
class icomponent {
public:
virtual ~icomponent() = default;
virtual std::string id() = 0;
};
// Sample components a, b and c
class component_a : public icomponent {
public:
virtual std::string id() override { return "component a"; }
};
class component_b : public icomponent {
public:
virtual std::string id() override { return "component b"; }
};
class component_c : public icomponent {
public:
virtual std::string id() override { return "component c"; }
};
// Interface defining a component manager
class iprocessing_component_manager
{
public:
virtual ~iprocessing_component_manager() = default;
virtual T* prepare() = 0;
// More members like init(), recycle() and dispose()
};
// An simple, possible implementation of component manager
class simple_processing_component_manager
: public iprocessing_component_manager
{
public:
virtual ~simple_processing_component_manager() = default;
// ... other implemented methods ...
virtual T* prepare()
{
// ... creation of component
}
};
// In the controller wrapper, the process method
template<typename ...T>
void process()
{
// This initialization is normally within the controller wrapper
std::unique_ptr<simple_processing_component_manager> component_mgr = std::make_unique<simple_processing_component_manager>();
// Convert to tuple
std::tuple<T...> components;
// Iterate over (component) types ...
for_each(components, [&](auto& comp) {
using component_t = typename std::remove_reference<decltype(comp)>::type;
// Steps would be ...
// Instantiate the component (doesn't work, just showing what I need to accomplish)
component_t* x = component_mgr->prepare<component_t>();
// ^^^^^^^^^^^^^
// Perform component execution ... here I just print the id of the component
std::cout << x->id() << "\n";
// After processing component_mgr recycle() and / or dispose() are called
delete x;
});
}
总而言之,典型的控制器用法如下所示:
controller c(/* some initialization parameters */);
result = c->process<component_a, component_c>(/* some more parameters */);
这将是我首选的使用方式,将组件作为可变参数模板参数传递。在控制器process
方法中,迭代并执行这些组件类型。我真的想用process
方法传递组件而不是控制器实例化。
我的基本问题依赖于组件管理器prepare
方法。 component_manager
及其prepare
方法的简单实现如下所示:
T* prepare(/*...*/)
{
return new T(); // Create component instance
}
但是,我将有不同的组件管理器实现,例如,我想通过使用对象池来回收和重用创建的组件指针。在这种情况下,我可能会有像
这样的东西return borrow_object<T>(/* some key */); // Get from pool, will be returned back to pool with `recycle`...
最后我将有各种不同的component_managers
,prepare
的每个实现和其他回收/处理方法会有所不同,但是,对于我需要组件类型T
的所有情况。但是......模板方法不能是虚拟的。我知道这个!
有没有办法解决上述问题,或者可能是一种更好的方法或设计解决这个问题?我一直坐着盯着这个太久了,所以如果我错过了一些非常简单的事情,请耐心等待。
谢谢你的时间!
答案 0 :(得分:0)
我不是继承和虚拟方法的专家......而且我不确定你理解你的确切要求......无论如何,正如你所说,模板方法不能是虚拟的。
所以你必须考虑到这一点。
但模板方法可以在模板类中调用虚方法。
所以我建议在prepare()
中创建虚拟iprocessing_component_manager
以返回icomponent
指针。
struct iprocessing_component_manager
{
virtual ~iprocessing_component_manager () = default;
virtual icomponent * prepare () = 0;
};
接下来,准备实现prepare()
template <typename T>
struct type_processing_component_manager
: public iprocessing_component_manager
{
virtual ~type_processing_component_manager () = default;
virtual T* prepare () override
{ return new T; }
};
观察prepare()
返回指向T
的指针,而不是指向icomponent
的指针。
现在,您可以编写一个可变参数模板tuple_processing_component_manager
,该模板继承自所有type_processing_component_manager<Ts>
,并使用模板(显然不是virtual
)prepare()
调用右侧(类型)依赖)虚拟继承prepare()
方法。
template <typename ... Ts>
struct tuple_processing_component_manager
: public type_processing_component_manager<Ts>...
{
virtual ~tuple_processing_component_manager () = default;
template <typename T>
T * prepare ()
{ return type_processing_component_manager<T>::prepare(); }
};
在主process()
中,您可以拥有基于可变参数处理组件管理器的component_mgr
auto component_mgr
{ std::make_unique<tuple_processing_component_manager<Ts...>>() };
并在lambda中使用它,如下所示
using component_t
= typename std::remove_reference<decltype(comp)>::type;
std::unique_ptr<component_t> x
{ component_mgr->template prepare<component_t>() };
std::cout << x->id() << "\n";
以下是一个完整的工作示例。
#include <tuple>
#include <memory>
#include <utility>
#include <iostream>
namespace detail
{
template <typename Tuple, typename F, std::size_t ... Is>
constexpr void for_each_impl (Tuple && tuple, F && f,
std::index_sequence<Is...>)
{
using swallow = int[];
(void)swallow { 1,
((void)f(std::get<Is>(std::forward<Tuple>(tuple))), 0)... };
}
}
template <typename Tuple, typename F>
constexpr void for_each (Tuple && tuple, F && f)
{
constexpr auto N
{ std::tuple_size<std::remove_reference_t<Tuple>>::value };
detail::for_each_impl(std::forward<Tuple>(tuple), std::forward<F>(f),
std::make_index_sequence<N>{});
}
struct icomponent
{
virtual ~icomponent () = default;
virtual std::string id () = 0;
};
struct component_a : public icomponent
{ virtual std::string id () override { return "component a"; } };
struct component_b : public icomponent
{ virtual std::string id () override { return "component b"; } };
struct component_c : public icomponent
{ virtual std::string id () override { return "component c"; } };
struct iprocessing_component_manager
{
virtual ~iprocessing_component_manager () = default;
virtual icomponent * prepare () = 0;
};
template <typename T>
struct type_processing_component_manager
: public iprocessing_component_manager
{
virtual ~type_processing_component_manager () = default;
virtual T* prepare () override
{ return new T; }
};
template <typename ... Ts>
struct tuple_processing_component_manager
: public type_processing_component_manager<Ts>...
{
virtual ~tuple_processing_component_manager () = default;
template <typename T>
T * prepare ()
{ return type_processing_component_manager<T>::prepare(); }
};
template <typename ... Ts>
void process ()
{
auto component_mgr
{ std::make_unique<tuple_processing_component_manager<Ts...>>() };
std::tuple<Ts...> components;
for_each(components, [&](auto& comp)
{
using component_t
= typename std::remove_reference<decltype(comp)>::type;
std::unique_ptr<component_t> x
{ component_mgr->template prepare<component_t>() };
std::cout << x->id() << "\n";
});
}
int main ()
{
process<component_a, component_b, component_c>();
}
如果您对std::tuple
的{{1}}以及components
处理不感兴趣,可以在递归{{1}中直接使用for_each()
结构}
type_processing_component_manager