Непрозрачный указатель на структуру с элементами шаблона

Предположим, я строю связанный список (реальная структура данных совершенно другая, но для вопроса достаточно связанного списка), чьи узлы выглядят как

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-х комментарий убедил меня, что я прошу слишком много гарантий от системы типов в то же время, что я пытаюсь обойти слишком много этих гарантий. Я вернусь к сдаче T быть void * за счет литья и косвенного обращения.

2

Решение

Пока тебя не волнует, что T вы больше всего хотите отличить его от другого типа — скажем, Uне так ли?
Вы, вероятно, хотите, чтобы следующее вызвало ошибку:

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

Есть несколько способов сделать ваш код проще, не жертвуя проверкой типов или производительностью во время выполнения:

  • Если вы используете C ++ 11, подумайте об использовании auto вместо того, чтобы явно называть тип при использовании ваших функций
  • Если node<T> очень часто встречается в вашем коде, вы можете установить глобальную область видимости typedef

Также обратите внимание, что в контексте node<T> определение, используя равнину node (без аргументов шаблона) допускается.

Если вы действительно хотите скрыть содержимое nodeрассмотреть возможность реализации Pimpl шаблон, как предложено mvidelgauz.

1

Другие решения

Если вы можете использовать boost, тогда boost :: any или boost :: option может помочь реализовать гетерогенные контейнеры.

Это то, что вы ищете?

#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
0

По вопросам рекламы [email protected]