Идиома Pimpl: Какой size_type использовать, если реализация неизвестна? - PullRequest
1 голос
/ 01 февраля 2010

У меня есть класс, который содержит массив элементов, и я хочу дать ему GetSize функцию-член. Но какой тип возврата я должен дать этой функции?

Я использую идиому pimpl, и поэтому в заголовочном файле неизвестно, что реализация будет использовать для хранения элементов. Поэтому я не могу просто сказать std::vector<T>::size_type, например:

class FooImpl;

class Foo {
  FooImpl* impl_;
public:
  TYPE GetSize(); // what TYPE??
};

Ответы [ 4 ]

1 голос
/ 01 февраля 2010

Если клиентский код может видеть только Foo (что является идиомой pimpl), тогда нет смысла определять конкретный size_type в конкретной реализации - он не будет виден / доступен для клиента тем не мение. Стандартные контейнеры могут это делать, поскольку они построены на так называемом «полиморфизме во время компиляции», в то время как вы специально пытаетесь использовать [потенциально] метод сокрытия реализации во время выполнения.

В вашей ситуации единственным выбором будет выбор целочисленного типа, которого «должно быть достаточно для всех возможных реализаций» (например, unsigned long), и придерживайтесь его.

Другой возможностью является использование типа uintptr_t, если он доступен в вашей реализации (он стандартизирован в C99, но не в C ++). Предполагается, что этот целочисленный тип охватывает весь диапазон адресов хранения, доступный программе, что означает, что его всегда будет достаточно для представления размера любого контейнера в памяти. Обратите внимание, что другие постеры часто используют ту же логику, но неправильно приходят к выводу, что подходящий тип для использования здесь - size_t. (Обычно это происходит из-за недостатка опыта реализации моделей не плоской памяти.) Если ваши контейнеры всегда основаны на физических массивах, size_t будет работать. Однако, если ваши контейнеры не всегда основаны на массивах, size_t даже не является удаленно правильным типом для использования здесь, так как его диапазон обычно меньше, чем максимальный размер не непрерывного (не основанного на массиве) контейнера.

Но в любом случае, независимо от того, какого размера вы в конечном итоге используете, было бы неплохо спрятать его за typedef-именем, как это делается в стандартных контейнерах.

1 голос
/ 01 февраля 2010

Общий тип для размеров в C ++ - size_t.Я бы использовал это.

Я имею в виду общий в нетехническом смысле.Это не имеет ничего общего с шаблонами.

Похоже, это было раньше: Когда мне следует использовать std :: size_t?

edit

После долгих обсуждений я немного исправлю свой ответ.

Если size_t такой же ширины, как указатель, используйте size_t.Если нет, используйте беззнаковое целое с той же шириной, что и указатель.

0 голосов
/ 01 февраля 2010

Вы можете последовать примеру STL и сделать size_type typedef, который опирается на FooImpl:

template<typename T> class s_type {
    public:
    typedef size_t type; // good default
};

class FooImpl;

// I'm only doing this specialization to show how it's done
// not because I think it's needed.  In general I'd use size_t.
template<> class s_type<FooImpl> {
    public:
    typedef uintptr_t type;
};

class Foo {
  FooImpl* impl_;

  public:
  typedef size_type s_type<FooImpl>::type;
  size_type GetSize();
};
0 голосов
/ 01 февраля 2010

size_type обычно используются, чтобы скрыть целочисленный тип (short против long против long long и т. Д.). Просто определите свой собственный Foo::size_type.

...