Заполнить шаблон одного класса из другого шаблона класса - PullRequest
1 голос
/ 28 сентября 2011

Если у меня есть два класса:

template <typename T>
struct Node
{
  ...
};

tempalte <typename T_Node, typename T>
struct NodeIterator
{
  T m_value;
};

NodeIterator<Node<int>, int>

, могу ли я вывести аргумент шаблона T из T_Node без класса Node, явно создавая typedef, подобный этому:

// To make it clear, yes I know this works, but I had to typedef the type
template <typename T>
struct Node
{
  typedef T node_type;
  ...
};

template <typename T_Node>
struct NoteIterator
{
  typedef typename T_Node::node_type node_type;

  node_type m_value;
};

NodeIterator<Node<int> >

Если нет, то есть ли причина, по которой я не могу этого сделать (компилятор уже знает о T_Node и типе T, который он принял), кроме "эта функция просто отсутствует в C ++" ?Я спрашиваю об этом, поскольку обычно есть веская причина для чего-то простого (по крайней мере, на первый взгляд), такого как пропущенное в языке.

Ответы [ 6 ]

2 голосов
/ 28 сентября 2011

Без typedef это невозможно. Дело в том, что компилятор не знает, что T_Node само по себе является экземпляром шаблона. Node<T> - это просто тип , ничего более.

C ++ знает три уровня сущностей: значения, типы и шаблоны. Node - это шаблон, а Node<T> - это тип. Когда ваш шаблон класса принимает параметр type , у вас больше нет возможности проверить природу этого типа.

Сопоставление с образцом посредством частичной специализации - единственный способ извлечения такой информации, и вам не придется обойтись без функционального метапрограммирования. Любая проверка типов обычно называется «чертой типа». Все это сводится к одному и тому же, очень похоже на то, что вы уже предложили, но, возможно, вот еще один, более общий способ:

template <typename> struct ClassWithOneArg;

template <template <typename> class C, typename T>
struct ClassWithOneArg<C<T>>
{
  typedef T value_type;
};

Теперь вы можете сказать: typedef typename ClassWithOneArg<T_Node>::value_type type;.

2 голосов
/ 28 сентября 2011

Почему бы вам не изменить NodeIterator на что-то подобное:

template <typename T>
struct NodeIterator
{
  typedef Node<T> node_type;

  node_type m_value;
};

, это должно позволить вам создавать объекты типа NodeIterator<int>.Я думаю, что это было бы элегантным решением.`

1 голос
/ 28 сентября 2011

Да. То, что вы пробовали, почти правильно, за исключением того, что вы забыли typename:

typedef typename T_Node::node_type node_type;
       //^^^^^^^ note this!

Вам необходимо написать ключевое слово typename, потому что вложенный тип node_type является зависимым типом .

0 голосов
/ 28 сентября 2011

Ответ - нет, вы не можете сделать это в C ++. Вот почему типы итераторов STL содержат те вложенные определения типов, которых вы пытаетесь избежать. Кроме того, полагаясь на эти вложенные типы, вы столкнетесь с проблемами, если захотите разрешить указатели на узлы (которые соответствуют всем требованиям для RandomAccessIterators). Вам нужно будет использовать классы признаков, если вы хотите включить необработанные указатели на узлы в качестве типов итераторов узлов, поскольку они не могут иметь вложенные типы.

0 голосов
/ 28 сентября 2011

Не думаю, что вы можете, но я не думаю, что вам это тоже нужно. Использование typedefs для этого является общепринятой практикой; посмотрите на стандартные контейнеры и их value_type и т. д. typedefs.

Вы упомянули в комментарии к другому ответу, что вы не хотите, чтобы NodeIterator знал о Node. Он не должен знать о Node конкретно; он просто требует, чтобы его аргумент шаблона был неким типом, который содержит в себе тип node_type. Это может быть Node или это может быть что-то еще, и NodeIterator не должен знать или заботиться.

0 голосов
/ 28 сентября 2011

Нет, вы не можете. Вам нужен typedef. C ++ не имеет никакой поддержки отражения времени компиляции, где эта функция будет соответствовать.

Причина, по которой его нет в языке, проста: никто не придумал хорошего предложения для такой функции в процессе стандартизации. Это, вероятно, потому, что такая функция не является тривиальной. Почему вы можете быть просто довольны получением параметров шаблона, существует множество других мест, которые необходимо учитывать, чтобы сделать объект в целом «круглым».

Вы могли бы разработать такое предложение, когда вас заинтересовали;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...