假设我正在建立一个链接列表(真正的数据结构完全不同,但链接列表足以满足问题),其节点看起来像
template <typename T>
struct node
{
struct node<T> *next;
T data;
};
对于我的数据结构,我有许多返回类型为struct node *
的函数,我希望用户将此类型视为不透明。在链表示例中,这样的函数可以是例如get_next(struct node<T> *n)
或insert_after(struct node<T> *x, struct node<T> *y)
。只有极少数功能,即分配node
s或获取/设置其data
字段的功能,需要了解T
的任何内容。
是否有更好的方法来忽略T
&#34;并且让用户只与typedef struct node * opaque_handle
之类的内容进行交互,以获得那些不必关心T
的功能?我的直觉反应,来自C,只是来往于void*
,但这听起来并不优雅。
编辑:CygnusX1 comment让我确信我在同一时间要求类型系统提供太多保证试图绕过太多这些保证。我会以牺牲铸造和间接为代价而让T
成为void *
。
答案 0 :(得分:1)
虽然您不关心ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
end
是什么,但您最希望将其与其他类型区分开来 - 比如说T
,不是吗?
您可能希望以下内容引发错误:
U
在不牺牲类型检查或运行时性能的情况下,有几种方法可以使代码更简单:
node<T>* elem1 = ...
node<U>* elem2 = ...
elem1 = elem2
而不是在使用函数时明确命名类型auto
在您的代码中非常常见,您可以设置全局范围node<T>
另请注意,在typedef
定义的上下文中,允许使用普通node<T>
(不带模板参数)。
如果您确实要隐藏node
的内容,请考虑按照mvidelgauz的建议实施pimpl模式。
答案 1 :(得分:0)
如果你可以使用boost,那么boost :: any或boost :: variant可能能够帮助实现异构容器。
这就是你想要的东西吗?:
#include <iostream>
#include <boost/any.hpp>
#include <list>
using Collection = std::list<boost::any>;
using Node = Collection::iterator;
static Collection anys;
template<typename T>
Node insert_after(T const& obj, Node start_pos = anys.end())
{
return anys.insert(start_pos, boost::any(obj));
}
void print_type(boost::any const& a)
{
if (a.type() == typeid(int)) { std::cout << "int" << std::endl; }
else if (a.type() == typeid(float)) { std::cout << "float" << std::endl; }
}
int main()
{
const auto node1 = insert_after(int(1));
const auto node2 = insert_after(float(2.57));
const auto node3 = insert_after(int(3));
std::cout << boost::any_cast<int>(*node1) << std::endl;
std::cout << boost::any_cast<float>(*node2) << std::endl;
std::cout << boost::any_cast<int>(*node3) << std::endl;
print_type(*node1);
print_type(*node2);
print_type(*node3);
return 0;
}
输出:
1
2.57
3
int
float
int