【发布时间】:2021-06-23 06:26:59
【问题描述】:
给定某种类型 T 的模板化包装器
template<typename T>
struct Wrapper {
T* value;
};
如果我想为包装器提供一些多态行为,我通常会使用一些带有 sfinae 的模板化运算符。例如演员:
template<typename Base>
template<typename Derived, enable_if_t<is_base_of<T,From>::value,int> = 0>
Wrapper<Base>::Wrapper(Wrapper<Derived> & other) : value(other.value) {
}
它适用于简单的情况。然而,当我开始创建复杂的层次结构时,我发现编译器不理解发生了什么。一个非常愚蠢的代码是
#include<memory>
#include<iostream>
using namespace std;
struct Base {
virtual ~Base() = default;
int i;
};
struct Derived : Base {
Derived(int in) {
this->i = in;
}
};
template<class T>
struct Wrapper {
Wrapper(T & v) : value(&v) {}
T* value;
};
template<typename T>
struct Interface {
virtual ~Interface() = default;
virtual T const & get() = 0;
};
template<typename T>
struct Something : Interface<T> {
Something(Wrapper<T> const & value) : pt(&value) {}
Wrapper<T>* pt;
T const & get() {return pt->value;}
};
void foo(unique_ptr<Interface<Base>> && p) {
std::cout << "I have interface to base" << p->get()->i;
}
int main() {
Derived v(42);
Wrapper<Derived> w(v);
foo(make_unique<Something<Derived>>(w) );
}
在这种代码中,Something 派生自 Interface,Derived 从 Base,所以原则上应该可以从 unique_ptr<Something<Derived>> 转到 unique_ptr<Interface<Base>>,我相信这样做没有太大的危险。
您将使用 SFINAE/is_base_of 机制定义哪些运算符(ctors、assign、conversions 等)?在哪里?是否有一些一般规则可以遵循?
【问题讨论】:
-
题外话:你的
Something构造函数分配给pt指向value的指针,它可能是一个临时对象。这可能会导致在构造结束时出现悬空引用。 -
对,应该是"Wrapper
&" -
您的
wrapper<T>包含一个T,要应用多态性,您需要T上的(智能)指针...否则您将进行对象切片。 -
也对,我修改以清除问题。主要关注的是界面。主要我不希望将 Derived 转换为 Base,但说该接口也适用于 Base。
标签: c++ templates polymorphism wrapper