[英]Template polymorphism and unique_ptr
I'm currently trying to program a pipeline, which is able to process different kind of data in every pipeline element.我目前正在尝试编写一个管道,它能够处理每个管道元素中的不同类型的数据。 Now I want to use
unique_ptr
s with some kind of template polymorphism and template specialization.现在我想使用具有某种模板多态性和模板特化的
unique_ptr
。
struct Start {}; // Dummy struct
template<typename In, typename Out>
class PipelineElement {
public:
virtual Out process(In in) = 0;
};
// partial template specialization for the first pipeline element
template<typename Out>
class PipelineElement<Start, Out> {
public:
virtual Out process() = 0;
};
class Producer : public PipelineElement<Start, int> {
int process() override { ... }
};
Now a function shall take a unique_ptr
of a partial specialized PipelineElement
.现在,函数应采用部分专用
PipelineElement
的unique_ptr
。 However, the following won't compile with the error message:但是,以下内容不会与错误消息一起编译:
auto Pipeline::setStart<int>(std::unique_ptr<PipelineElement<Start,int>,std::default_delete<PipelineElement<Start,int>>>)': cannot convert argument 1 from 'std::unique_ptr<Producer,std::default_delete<Producer>>' to 'std::unique_ptr<PipelineElement<Start,int>,std::default_delete<PipelineElement<Start,int>>>
auto Pipeline::setStart<int>(std::unique_ptr<PipelineElement<Start,int>,std::default_delete<PipelineElement<Start,int>>>)':无法从 'std::unique_ptr<Producer 转换参数 1, std::default_delete<Producer>>' 到 'std::unique_ptr<PipelineElement<Start,int>,std::default_delete<PipelineElement<Start,int>>>
class Pipeline {
template<typename Out>
static auto setStart(std::unique_ptr<PipelineElement<Start, Out>> element) { ... }
};
int main() {
Pipeline::setStart(std::make_unique<Producer>());
}
If I use regular pointers instead, it does compile without any errors.如果我改用常规指针,它会编译而不会出现任何错误。
Why does the version with normal pointers compile, and the version with smart pointers doesn't?为什么带有普通指针的版本可以编译,而带有智能指针的版本却不能?
class Pipeline {
template<typename Out>
auto setStart(PipelineElement<Start, Out>* element) { ... }
};
int main() {
Pipeline::setStart(new Producer());
}
The PipelineElement
doesn't have a virtual destructor. PipelineElement
没有虚拟析构函数。 So deleting Producer
by deleting pointer to PipelineElement
will cause an error.所以通过删除指向
PipelineElement
指针来删除Producer
会导致错误。
Edit: due to @RemyLebeau info.编辑:由于@RemyLebeau 信息。 Unfortunately,
std::unique_ptr
fails to figure this out.不幸的是,
std::unique_ptr
这个问题。 The compilation issue is because compiler fails to deduce the template parameters of setStart
.编译问题是因为编译器无法推导出
setStart
的模板参数。 Note: please, in the future provide genuine error messages and not fake ones.注意:请在未来提供真正的错误信息,而不是虚假信息。
The ability to deduce template parameters is limited and doesn't try most forms of conversions except some trivial ones during the template parameters search.推断模板参数的能力是有限的,除了在模板参数搜索过程中一些微不足道的转换外,不会尝试大多数形式的转换。 If you don't want to specify the template parameters each time it is adviced to accept a more general type of input and impose SFINEA-based restrictions:
如果您不想在每次建议接受更一般类型的输入并施加基于 SFINEA 的限制时都指定模板参数:
Here, I wrote an example based on restricting input unique_ptr<T>
to have T
inherit from PipelineElementBase
.在这里,我编写了一个基于限制输入
unique_ptr<T>
以让T
从PipelineElementBase
继承的示例。
#include <iostream>
#include <memory>
#include <type_traits>
using namespace std;
struct Start {}; // Dummy struct
class PipelineElementBase
{
public:
virtual ~PipelineElementBase() = default;
};
template<typename In, typename Out>
class PipelineElement : public PipelineElementBase
{
public:
~PipelineElement() { cout << "~PipelineElement<In,Out>" << endl; }
virtual Out process(In in) = 0;
};
// partial template specialization for the first pipeline element
template<typename OutParam>
class PipelineElement<Start, OutParam> : public PipelineElementBase
{
public:
using Out = OutParam;
~PipelineElement() { cout << "~PipelineElement<Start,Out>" << endl; }
virtual Out process() = 0;
};
class Producer : public PipelineElement<Start, int>
{
public:
~Producer() { cout << "~Producer" << endl; }
int process() override { return 1; }
};
class Pipeline
{
public:
template<typename PE, std::enable_if_t<std::is_base_of_v<PipelineElementBase, PE>,int> = 0>
static auto setStart(std::unique_ptr<PE> element)
{
using Out = typename PE::Out;
return 1;
}
};
int main()
{
Pipeline::setStart(std::make_unique<Producer>());
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.