Позначка C ++ як застаріла


147

У мене є метод в інтерфейсі, який я хочу застаріти за допомогою портативного C ++. Коли я погукався за це, все, що було, було специфічним для Microsoft рішенням; #pragma застарілий і __declspec (застарілий) .

Другим призовим рішенням було б вирішити MSVC та рішення GCC.
Дякую

Відповіді:


193

У C ++ 14 ви можете позначити функцію як застарілу за допомогою [[deprecated]]атрибута (див. Розділ 7.6.5 [dcl.attr.deprecated]).

Атрибут-маркер deprecated можна використовувати для імен міток і юридичних осіб, використання яких по- , як і раніше допускається, але не рекомендується для якої - то причини.

Наприклад, ця функція fooзастаріла:

[[deprecated]]
void foo(int);

Можна надати повідомлення, яке описує, чому назву чи сутність застаріли:

[[deprecated("Replaced by bar, which has an improved interface")]]
void foo(int);

Повідомлення повинно бути літеральним рядком.

Детальнішу інформацію див. У розділі "Позначення як застаріле в C ++ 14" .


Чи можете ви використовувати [[застаріле]] у макросі?
Даніель Райан

2
@Zammbi Ви повинні мати можливість, оскільки макрос обробляється препроцесором перед компіляцією. [[застарілий]] повинен з’явитися (і дозволити компілятору виводити відповідні попередження), де оцінюється макрос.
Флоріан Кастеллан

129

Для цього слід зробити фокус:

#ifdef __GNUC__
#define DEPRECATED(func) func __attribute__ ((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED(func) __declspec(deprecated) func
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED(func) func
#endif

...

//don't use me any more
DEPRECATED(void OldFunc(int a, float b));

//use me instead
void NewFunc(int a, double b);

Однак у вас виникнуть проблеми, якщо тип повернення функції має коми у своєму імені, наприклад, std::pair<int, int>тому що препроцесор інтерпретується як передача 2-х аргументів на ЗАМЕЧАНИЙ макрос. У такому випадку вам доведеться ввести тип повернення.

Edit: простий (але , можливо , менш широко сумісний) версія тут .


6
Замість #error, краще буде #define DEPRECATED (func) func
CesarB

1
mxp: Депресія є лише попередженням, і тому я б сказав, що попередження про те, що воно не підтримується, - все, що вам потрібно.
Леон Тіммерманс

1
Так, я б пішов на "# попередження. Вам потрібно реалізувати DEPRECATED для цього компілятора", або щось подібне. Якщо це неможливо, то носильник може #define ВИЗНАЧЕНО (FUNC) FUNC та жити без нього.
Стів Джессоп

2
На жаль, не існує стандартного способу вивести попередження про компіляцію в C ++: P #pragma повідомляти не доведеться.
Майкл Плачінг

3
Синтаксис атрибутів gcc дозволяє атрибуту знаходитись там же, що і __declspec(deprecated)зараз, тому макрос можна спростити.
bames53

57

Ось спрощена версія моєї відповіді 2008 року :

#if defined(__GNUC__) || defined(__clang__)
#define DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED __declspec(deprecated)
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED
#endif

//...

//don't use me any more
DEPRECATED void OldFunc(int a, float b);

//use me instead
void NewFunc(int a, double b);

Дивитися також:


17
Як у вас [[deprecate]]застарілі макроси? :-)
graham.reeds

3
Я не бачу жодної суттєвої різниці між цими двома відповідями. Чому ви опублікували це вдруге?
Томаш Зато - Відновіть Моніку

4
Вам не доведеться обертати його навколо функції, а це DEPRECATED void foo(...);замістьDEPRECATED(void foo(...));
dshepherd

12
Ви повинні були відредагувати відповідь 2008 року, а не публікувати нову.
Яків Галка

4
Це може бути не настільки сумісно, ​​як моя інша відповідь, тому я додав це окремо.
Майкл Плачінг

22

У GCC ви можете оголосити свою функцію з атрибутом, який застарів так:

void myfunc() __attribute__ ((deprecated));

Це призведе до попередження часу компіляції, коли ця функція використовується у файлі .c.

Додаткову інформацію можна знайти в розділі "Діагностичні прагми" на веб- сайті http://gcc.gnu.org/onlinedocs/gcc/Pragmas.html


8

Ось більш повна відповідь на 2018 рік.

У наші дні дуже багато інструментів дозволяють не просто позначати щось як застаріле, але й надавати повідомлення. Це дозволяє вам повідомити людям, коли щось застаріло, і, можливо, вказати на заміну.

У підтримці компілятора все ще багато:

  • C ++ 14 підтримує [[deprecated]]/ [[deprecated(message)]].
  • __attribute__((deprecated)) підтримується GCC 4.0+ та ARM 4.1+
  • __attribute__((deprecated))і __attribute__((deprecated(message)))підтримується для:
    • GCC 4.5+
    • Кілька компіляторів, які маскуються під GCC 4.5+ (налаштуванням __GNUC__/ __GNUC_MINOR__/ __GNUC_PATCHLEVEL__)
    • Компілятор Intel C / C ++ повертається щонайменше до 16 (ви не можете довіряти __GNUC__/ __GNUC_MINOR__вони просто встановлюють його до будь-якої версії GCC встановлена)
    • ARM 5.6+
  • MSVC підтримує __declspec(deprecated)з 13.10 (Visual Studio 2003)
  • MSVC підтримує __declspec(deprecated(message))з 14.0 (Visual Studio 2005)

Ви також можете використовувати [[gnu::deprecated]]в останніх версіях clang в C ++ 11 на основі __has_cpp_attribute(gnu::deprecated).

У Хедлі у мене є кілька макросів, які автоматично обробляють все це, що я постійно оновлюю, але поточна версія (v2) виглядає приблизно так:

#if defined(__cplusplus) && (__cplusplus >= 201402L)
#  define HEDLEY_DEPRECATED(since) [[deprecated("Since " #since)]]
#  define HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]]
#elif \
  HEDLEY_GCC_HAS_EXTENSION(attribute_deprecated_with_message,4,5,0) || \
  HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
  HEDLEY_ARM_VERSION_CHECK(5,6,0)
#  define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
#  define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
#elif \
  HEDLEY_GCC_HAS_ATTRIBUTE(deprcated,4,0,0) || \
  HEDLEY_ARM_VERSION_CHECK(4,1,0)
#  define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))
#  define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
#elif HEDLEY_MSVC_VERSION_CHECK(14,0,0)
#  define HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since))
#  define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)
#  define HEDLEY_DEPRECATED(since) _declspec(deprecated)
#  define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
#else
#  define HEDLEY_DEPRECATED(since)
#  define HEDLEY_DEPRECATED_FOR(since, replacement)
#endif

Я залишу це як вправу, щоб зрозуміти, як позбутися макросів *_VERSION_CHECKі, *_HAS_ATTRIBUTEякщо ви не хочете користуватися Хедлі (я писав Хедлі в основному, тому мені не доведеться думати про це регулярно).

Якщо ви використовуєте GLib, ви можете використовувати макроси G_DEPRECATEDта G_DEPRECATED_FOR. Вони не такі надійні, як у Hedley, але якщо ви вже використовуєте GLib, нічого додати.


4

Для роботи з портативними проектами майже неминуче, що вам в якийсь момент потрібен розділ попередньо оброблених альтернатив для різних платформ. #ifdef це #ifdef це тощо.

У такому розділі ви могли б дуже умовно визначити спосіб знецінення символів. Як правило, я вважаю, щоб визначити макрос "попередження", оскільки більшість ланцюжків інструментів підтримують застереження компілятора. Тоді ви можете продовжувати використання конкретного макросу попередження про депрекацію тощо. Для платформ, що підтримують спеціальні методи депрекації, ви можете використовувати це замість попереджень.


1

Для Intel Compiler v19.0 використовуйте це як __INTEL_COMPILERоцінку для 1900:

#  if defined(__INTEL_COMPILER)
#    define DEPRECATED [[deprecated]]
#  endif

Працює на наступних мовних рівнях:

  • Підтримка C ++ 17 (/ Qstd = c ++ 17)
  • Підтримка C ++ 14 (/ Qstd = c ++ 14)
  • Підтримка C ++ 11 (/ Qstd = c ++ 11)
  • Підтримка C11 (/ Qstd = c11)
  • Підтримка C99 (/ Qstd = c99)

У Intel Compiler є помилка, яка не підтримує [[deprecated]]атрибут певних мовних елементів, які роблять усі інші компілятори. Наприклад, компілюйте v6.0.0 (помітно чудовий) {fmtlib / fmt} бібліотеки на GitHub з Intel Compiler v19.0. Це зламається. Потім перегляньте виправлення в GitHub .


Це неправильно; Атрибути C ++ не працюють в режимі C на ICC. Приклад . __attribute__((deprecated)), OTOH, працює на C і C ++, повертаючись принаймні до ICC 13.0, ймовірно, набагато далі (Intel прагне не документувати подібні речі, тому я не можу бути впевнений).
nemequ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.