Где я должен поместить typedef при использовании в сигнатурах методов в C ++?

Я использую класс Необязательный , очень похожий на класс boost. По семантическим причинам я переключил атрибут одного и того же (структурированного) типа в некоторые определения классов (а следовательно, и подписи методов) с обязательного на необязательный. Итак, в каждом файле заголовка связанного класса я включил заголовок с определением Необязательный , а также typedef для облегчения ввода текста (см. комментарии CHANGE); проходы читаются так:

#include <MyAttrType.h>
#include <Optional.h>                          // CHANGE
typedef Optional<MyAttrType> OptionalAttrType  // CHANGE

class MyClassX
{
// ...

Сегодня я запускаю Cppcheck 1.68 в проекте и получил этот стиль предупреждения:

  

typedef 'OptionAttrType' скрывает typedef с тем же именем.

Как я могу избавиться от предупреждений стиля тезисов, не делая что-то плохое?


Примечания:

  • MyAttrType в настоящее время не зависит от Optional ( потому что он определен в начале истории проекта, а в качестве опции - последний раз).
  • Я думаю о том, чтобы вводить новый заголовок только для этой цели. Но, может быть, есть лучшие варианты?
  • Я предполагаю, что это может быть признаком плохого дизайна, чтобы иметь много классов с одним и тем же необязательным атрибутом, но я не уверен в своем специальном случае. Код в настоящее время изменяется для достижения более приоритетных целей.
  • , конечно, MyAttrType, OptionalAttrType, и MyClassX не являются фактическими именами
3 голоса | спросил Wolf 5 Jpm1000000pmMon, 05 Jan 2015 15:14:34 +030015 2015, 15:14:34

3 ответа


2

Обычно я использую один из двух способов.

  1. Первый способ - typedef в месте первого объявления.
  2. Второй способ заключается в typedef в каждом месте использования и сделать его видимым только для это место использования (путем помещения его внутрь класса или метода, который его использует).

(1) Поместите typedef близко к типу, который завернут.

/* MyAttrType.h */

#include <Optional.h>

// README : See Optional<MyAttrType> at the end of this header

struct MyAttrType
{
    // ....
};

// (put the typedef here)
typedef Optional<MyAttrType> OptionalMyAttrType;

/* ---------------------------- */
/* Every other C++ source files */
#include "MyAttrType.h"

// .... Any code can use OptionalMyAttrType there.

(2) Сделать typedef видимым только для каждого класса, который его использует.

/* MyAttrType.h */

namespace my_pod_types
{
    struct MyAttrType { /* ... */ };
}

// (nothing else outside.)

/* ---------------------------- */
/* Every other C++ source files */

#include "MyAttrType.h"
#include "Optional.h"

class MyClassX
{
private:
    typedef Optional<my_pod_types::MyAttrType> OptionalMyAttrType;
public:
    // ...
private:
    OptionalMyAttrType m_optAttr;
};

В большинстве случаев подходящий мне шаблон - это std::unique_ptr и std::shared_ptr. Кроме того, я просто решаю, что класс будет либо использовать так или иначе, а затем typedef, что оболочка смарт-указателя как «MyClassOnePtr». Дракониан, но главный автор библиотеки должен знать, что лучше всего подходит для библиотеки большую часть времени.

Если не очевидно, какой из двух интеллектуальных указателей должен быть предпочтительным, тогда я не буду помещать typedef в первый заголовок (так что я не буду использовать параметр # 1, если выбор не очевиден.)

В большинстве случаев вы поймете, что опция № 2 не всегда защищает использование Optional<T> от конечного пользователя. То есть для логики приложения могут потребоваться пользователи MyClassX для работы с Optional<T> при взаимодействии с ним. Когда это произойдет, вы больше не сможете скрыть это. Это не деталь реализации; это часть видимой поверхности.

Наконец, вы должны знать о ограничении на C ++ для форварда-объявления вещей. А именно, бывают случаи, когда C ++ должен знать фронт:

  • Размер обертываемого типа;
  • Существование конструктора и деструктора по умолчанию;
  • И так далее.

См. этот вопрос о Stackoverflow (о unique::ptr) для примеров таких ограничений.


Еще одна несвязанная вещь, которую я хотел бы поделиться, прочитав ixrec ответ.

Я начал следовать политике «ничего в политике имен по умолчанию» после обнаружения того, что вы не можете получить Doxygen (широко используемую документацию на C ++ для генератора HTML) для создания хорошо организованной документации, если вы не классифицируете свои классы с помощью пространств имен. Кажется, неважно, как вы называете эти пространства имен; до тех пор, пока Doxygen видит их как отличные, и пользователи не жалуются на него, любой подход к пространству имен будет хорошим.

ответил rwong 6 AMpMon, 06 Apr 2015 02:29:07 +030029Monday 2015, 02:29:07
0

Если OptionalAttrType является частью открытого API, определенного этими заголовками, тогда я бы использовал другое имя для вашего typedef.

Если OptionAttrType - это деталь реализации, о которой вы не должны знать, то эти заголовки должны были помещать ее в пространство имен, чтобы предотвратить подобные конфликты. Поскольку они этого не сделали, вам нужно как-то обойти это.

Поскольку вы задаете этот вопрос, я предполагаю, что вы ожидаете столкнуться с большим количеством этих столкновений в будущем, поэтому вам нужно долгосрочное решение. Если вы не можете изменить все заголовки и исходные файлы, на которые вы хотите использовать пространства имен или более согласованные имена классов, единственное общее решение, о котором я могу думать, - это выбрать префикс или суффикс, который вряд ли столкнется с чем-либо (например, OptionalAttrType_TD) и начнет использовать это для всех ваших typedefs.

Менее общая, но, возможно, более практичная альтернатива - просто скрыть это предупреждение. В главе 6 руководства Cppcheck описываются все способы, с помощью которых можно подавить определенное предупреждение от этого инструмента.

ответил Ixrec 5 Jpm1000000pmMon, 05 Jan 2015 23:28:32 +030015 2015, 23:28:32
0

Есть три ошибки:

  1. Заголовки объявляют имя в пространстве имен, не являющемся приватным для вашей библиотеки, в котором у них нет бизнес-объявления.
  2. Кажется, вы не убедитесь, что в вашей библиотеке есть только одно определение.
  3. Вы пытаетесь закрыть предупреждение вместо исправления этой ошибки.

Что вы должны сделать, это один из:

  1. Сделайте его частью вашего интерфейса.
  2. Или спрячьте это в пространстве имен ваших библиотек (возможно, в вложенном пространстве имен internal или таких).
  3. Или полностью удалить его и записать полные имена.

Если вы выберете вариант 1 или 2, убедитесь, что он определен только в одном месте.

ответил Deduplicator 6 AMpMon, 06 Apr 2015 03:33:05 +030033Monday 2015, 03:33:05

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132