假设我正在编写容器类template <typename T> class MyContainer
,并且由于某种原因,我想传递类型T
的对象,其类型对用户是隐藏的。特别是,我想确保MyContainer::Foo
的所有输入首先通过MyContainer::HideType
。
template <typename T>
class MyContainer {
public:
... constructors and stuff...
HidesType& HideType(T&);
T& UnhideType(HidesType&);
void Foo(HideType&);
... some other stuff...
};
现在我想知道HidesType可以/应该是什么。一些选项是:
struct HidesType {
HidesType(T& data) : data_(data) { }
T& data_;
};
HidesType HideType(T& data) { return HidesType(data); }
union HidesType { T data_; };
HidesType& HideType(T& data) { return reinterpret_cast<HidesType&>(data); }
class HidesType : public T { };
HidesType& HideType(T& data) { return static_cast<HidesType&>(data); }
第一个问题是用户无法将T
个对象保留为
MyContainer<T>::HidesType tmp(HideType(t_obj));
因为tmp
超出范围后t_obj
将无效。另外,我不确定编译器是否会完全优化HidesType。
第二个问题是我不知道reinterpret_cast是否安全(例如,是否会出现任何对齐问题?)。
第三个问题是,T
可能会被标记为final
,而HidesType&amp;皈依T&amp;隐式。
任何想法或建议都将不胜感激。
修改
隐藏的主要目的是使HidesType
抽象并与T
区分开来。
解释导致这个问题的所有背景将是很麻烦的。现在,让我们假设函数MyContainer::Foo
基本上作为输入T
,但是,我不希望用户知道/使用它,特别是接口可能在将来发生变化。
正确的用例可能是:
MyContainer<T>::HidesType handle = MyContainer<T>::HideType(t_obj);
... do something ...
... perhaps t_obj.~T(); ...
... do something ...
my_container.Foo(handle);
无用的用例:
MyContainer<T>::HidesType handle = MyContainer<T>::HideType(t_obj);
... do something ...
my_container.Foo(some_other_t_obj);
答案 0 :(得分:0)
您希望类型H
只能由MyContainer<T>
实例化或修改。
实现这一目标的简单方法是使用private
构造函数和赋值运算符的类类型,移动构造函数除外,MyContainer<T>
为friend
。
您可以move
指定的T
对象,既可以提高效率,也可以不必要地将其设置为可复制。如果是,那么H
将不保证是可复制的。但是,正如我所看到的,它应该是可以移动的。
答案 1 :(得分:0)
您可以执行以下操作:
template <typename T>
class MyContainer {
public:
class HandleType {
public:
friend class MyContainer;
HandleType(const HandleType& rhs) = default;
HandleType(HandleType&& rhs) = default;
HandleType& operator =(const HandleType& rhs) = default;
HandleType& operator =(HandleType&& rhs) = default;
private:
// only MyContainer can construct this class
explicit HandleType(const T& t) : t(t) {}
private:
T t;
};
HandleType HideType(const T& t) { return HandleType(t); }
T& UnhideType(HandleType& handle) { return handle.t; }
void Foo(HandleType&);
};