typedef и неполный тип - PullRequest
       8

typedef и неполный тип

8 голосов
/ 19 июня 2010

В последнее время у меня много проблем с typedef и неполным типом, когда я изменил определенные контейнеры, распределители в моем коде.

То, что у меня было ранее

struct foo;//incomplete type.
typedef std::vector<foo> all_foos;
typedef all_foos::reference foo_ref;

Хотя не совсем не уверен,приведенные выше строки являются законными, но это работало на каждой реализации, которую я использовал.Когда я подумал, что могу выполнить работу с std::tr1::array, изменил две вышеупомянутые строки на

typedef std::tr1::array<foo,5> all_foos;
typedef all_foos::reference foo_ref;

Здесь все ломается, так как компилятор пытается создать экземпляр array и терпит неудачу, поскольку foo не завершентип.Все, что мне было нужно, это ссылка на foo, и он не особо интересовался «другими частями» массива.foo определенно будет полностью доступен, когда я создаю такой массив.

То же самое проблема, когда typedef std::allocator<foo>::pointer foo_ptr был заменен на typedef stack_alloc<foo,10>::pointer foo_ptr.где реализация stack_alloc похожа на

template<typename T,unsigned N>
struct stack_alloc
{
  typedef T* pointer;
  typedef std::tr1::aligned_storage<sizeof(T)*N, std::tr1::alignment_of<T>::value> buffer;
};

Предполагая, что value_type, pointer, reference, iterator и т. д. не зависят от полноты T, и зная, чтокласс не может быть создан без завершенного типа, как такая typedef может быть сделана общим способом независимо от конкретного контейнера или распределителя?

ПРИМЕЧАНИЕ:

  • Просто для полноты, в «реальном» коде я использую небольшую локальную память с vector вместо ее замены на std::array, хотя проблема остается той же.
  • stack_alloc код далек от завершения и показывает только часть проблемы.
  • Я знаю, что массив, sizeof и т. Д. Должен иметь полный доступный тип.Но я НЕ создаю объект типа all_foos с неполным foo.
  • Я утверждаю, что указатель, ссылка и т. Д. Не должны зависеть от полноты типа.В противном случае конструкция типа struct foo{ foo_ptr p;}; не может быть определена.Хотя, вероятно, foo_ref не может быть ничем иным, чем foo&, но foo_ptr может быть.Удивительно, но реализация GCC не имеет вложенного типа указателя для tr1::array.
  • В основном знают, что нельзя сделать, и заинтересованы знать, что можно сделать в этой ситуации.Поэтому ожидаем хорошего дизайна в качестве решения.

Ответы [ 2 ]

7 голосов
/ 19 июня 2010

Тип должен быть завершен для использования в стандартном контейнере, иначе поведение не определено (§17 .4.3.6 / 2).Поэтому единственное стандартное решение - не делать это typedef до тех пор, пока класс не будет определен.

Я не понимаю, для чего предназначен промежуточный контейнер:вам просто нужно сначала определить полный тип.Чтобы получить typedef, определенный в классе, необходимо создать экземпляр класса , что означает, что вся вещь должна иметь возможность использовать T по желанию.* Например, stack_alloc должен иметь T быть полным типом (для работы sizeof(T)), в противном случае класс не может быть создан.Если класс не может быть создан, вы не можете получить typedef из него.Ergo, вы никогда не получите typedef из него, если T будет неполным.

2 голосов
/ 19 июня 2010

Компилятор не знает размер неполного типа, поэтому он не может ни создать его экземпляр, ни выделить для него память. Наличие указателя на объект (например, typedef std::tr1::array<foo*, 5> all_foos;) вместо экземпляра самого объекта решает эту проблему.

...