2

假设我正在构建一个链表(实际的数据结构完全不同,但一个链表就足够了),其节点看起来像

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)。只有很少的功能,即分配nodes 或获取/设置其data字段的功能,需要了解有关T.

有没有更好的方法来“忽略T”并让用户只与typedef struct node * opaque_handle那些不需要关心的功能进行交互T?我的直觉反应,来自 C,只是投到和从void*,但这听起来不是很优雅。

编辑: CygnusX1 的评论让我确信,我在试图规避太多这些保证的同时,我要求类型系统提供太多保证。我将退回到以强制转换和间接Tvoid *代价。

4

2 回答 2

1

While you don't care about what T is, you most like want to differenciate it from a different type - say U, don't you? You probably want the following to raise an error:

node<T>* elem1 = ...
node<U>* elem2 = ...
elem1 = elem2

There are a few ways to make your code simpler without sacrificing the type checking or run-time perforamce:

  • If you use C++11, consider using auto instead of explicitly naming the type when using your functions
  • If node<T> is very common in your code, you can set a global-scope typedef

Also note, that in the context of node<T> definition, using a plain node (without template arguments) is allowed.

If you really want to hide the contents of the node, consider implementing the pimpl pattern as suggested by mvidelgauz.

于 2016-06-25T17:50:01.820 回答
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
于 2016-06-25T18:23:42.310 回答