В C/С++ существует ли директива, подобная #ifndef для typedefs?

Если я хочу определить значение, только если оно не определено, я делаю что-то вроде этого:

#ifndef THING
#define THING OTHER_THING
#endif

Что делать, если THING является идентификатором typedef 'd и не определен? Я хотел бы сделать что-то вроде этого:

#ifntypedef thing_type
typedef uint32_t thing_type
#endif

Проблема возникла из-за того, что я хотел проверить, не указала ли внешняя библиотека тип boolean, но я был бы открыт для получения более общего решения.

Ответ 1

Нет такого объекта в С++ на стадии предварительной обработки. На max может делать

#ifndef thing_type
#define thing_type uint32_t 
#endif

Хотя это не хорошая практика кодирования, и я не предлагаю этого.

Ответ 2

В языке нет такой вещи, и она не нужна. В рамках одного проекта вы не должны иметь одинаковый псевдоним typedef, ссылающийся на разные типы когда-либо, поскольку это является нарушением ODR, и если вы собираетесь создать один и тот же псевдоним для одного и того же типа, тогда просто сделайте это. Язык позволяет вам выполнять один и тот же typedef столько раз, сколько пожелаете, и обычно будет использовать этот ODR (в пределах одной единицы перевода):

typedef int myint;
typedef int myint;       // OK: myint is still an alias to int
//typedef double myint;  // Error: myint already defined as alias to int

Если то, что вы намереваетесь сделать, это реализовать часть функциональности для разных типов, используя typedef для определения того, что использовать, тогда вы должны смотреть на шаблоны, а не на typedefs.

Ответ 3

С++ не предоставляет никакого механизма для проверки кода присутствия typedef, лучшее, что у вас может быть, это что-то вроде этого:

#ifndef THING_TYPE_DEFINED
#define THING_TYPE_DEFINED
typedef uint32_t thing_type 
#endif

EDIT:
Как @David, верно в его комментарии, это отвечает на вопрос как? но важно, почему? Это можно сделать так, как описано выше. Если вы хотите сделать это и все, но важно, что вам, вероятно, не нужно это делать, @David ответ и комментарий объясняют детали, и я думаю, что это правильно отвечает на вопрос.

Ответ 4

Директивы препроцессора (например, #define) - это инструменты для замены текста, которые ничего не знают о языке программирования, поэтому они не могут действовать на каких-либо определениях на уровне языка.

Существует два подхода к тому, чтобы убедиться, что тип определен только один раз:

  • Структурируйте код так, чтобы каждое определение имело свое место, и нет необходимости в нескольких определениях
  • #define макрос препроцессора рядом с типом и используйте #ifndef для проверки определения макроса перед определением типа.

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

Ответ 5

Это может напрямую не ответить на вопрос, а послужить возможным решением вашей проблемы.

Почему бы не попробовать что-то вроде этого?

#define DEFAULT_TYPE int // just for argument sake
#ifndef MY_COOL_TYPE
     #define MY_COOL_TYPE DEFAULT_TYPE
#endif
typedef MY_COOL_TYPE My_Cool_Datatype_t;

Затем, если вы хотите настроить тип, вы можете определить MY_COOL_TYPE где-то выше этого (например, в заголовке "configure", который включен в начало этого заголовка) или передать его в качестве аргумента командной строки при компиляции (как насколько я знаю, вы можете сделать это с GCC и LLVM, а может быть и с другими). ​​

Ответ 6

Проблема на самом деле является реальной PITA, потому что некоторые API или SDK переопределяют часто используемые вещи. У меня возникла проблема с тем, что заголовочные файлы для программного обеспечения для обработки карт (ГИС) переопределяли ключевые слова TRUE и FALSE (обычно используемые Windows SDK) для целых литералов вместо истинных и ложных ключевых слов (очевидно, что это может сломать SOMETHING). И да, знаменитая шутка "#define true false" имеет значение.

define никогда не будет чувствовать typedef или константу, объявленную в коде C\С++, потому что препроцессор не анализирует код, он только сканирует # операторов. И он модифицирует код перед его синтаксическим анализатором. ТАК, в общем, это невозможно.

https://msdn.microsoft.com/en-us/library/5xkf423c.aspx?f=255&MSPPError=-2147217396  До сих пор он не переносится, хотя есть известный запрос на его реализацию в GCC. Я думаю, он также считается "расширением" в MSVC. Это оператор компилятора, а не предпроцессорный оператор, поэтому он не будет "чувствовать" определенные макросы, он обнаружил бы только typedefs вне тела функции. "полный тип" означает, что он будет реагировать на полное определение, игнорируя такие утверждения, как "class SomeClass;". Используйте его на свой страх и риск.

Изменить: по-видимому, он также поддерживается на MacOS сейчас и компилятором Intel с флагом -fms-dialect (AIX\Linux?)

Ответ 7

Как уже говорили другие, таких вещей нет, но если вы попытаетесь создать псевдоним для другого типа, вы получите ошибку компиляции:

typedef int myInt;
typedef int myInt;    // ok, same alias
typedef float myInt;  // error

Тем не менее, существует предмет, называемый ctag для определения того, где определен typedef.

Ответ 8

Нет ничего подобного, чего вы хотели. У меня была такая же проблема с библиотеками, которые включают их typedefs для таких вещей, как bool. Это становится проблемой, когда они просто не заботятся о том, что вы используете для bool, или если любые другие библиотеки могут делать то же самое!

Итак, вот что я делаю. Я редактирую файл заголовка для libs, которые делают такие вещи, и нахожу typedef bool и добавляю следующий код:

#ifdef USE_LIBNAME_BOOL
typedef unsigned char bool; // This is the lib bool implementation
#else
#include <stdbool.h>
#endif

Обратите внимание, что я включил, если я не хотел использовать собственный libs bool typdef. Это означает, что вам нужна поддержка C99 или позже.

Ответ 9

Как уже упоминалось ранее, это не включено в стандарт С++, но вы можете использовать autotools для получения той же функциональности.

Вы можете использовать макрос ac_cxx_bool, чтобы убедиться, что bool определен (или разные подпрограммы для разных типов данных).

Ответ 10

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

Ответ 11

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

Ответ 12

Без использования макроса вы можете определить, определяется ли тип typedef области пространства имен, проверяя, не скомпилирован ли компиляция. Если это typedef, вложенный в структуру SFINAE, можно использовать.

Для области typedef пространства имен вы можете сделать оба одновременно:

typedef int some_type
#define some_type some_type

И затем:

#ifdef some_type
    some_type some_var;
#endif

Это some_type - это макрос препроцессора и typedef.