ทำเครื่องหมาย C ++ ว่าเลิกใช้แล้ว


147

ฉันมีวิธีการในอินเทอร์เฟซที่ฉันต้องการคัดค้านด้วยพกพา C ++ เมื่อฉัน Googled สำหรับสิ่งนี้ทั้งหมดที่ฉันได้รับคือโซลูชันเฉพาะของ 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”


คุณสามารถใช้ [[เลิกใช้แล้ว]] ในแมโครได้หรือไม่?
Daniel Ryan

2
@Zammbi คุณควรสามารถทำได้เนื่องจากแมโครนั้นได้รับการจัดการโดยตัวประมวลผลก่อนที่จะรวบรวม [[เลิกใช้แล้ว]] ควรปรากฏขึ้น (และให้คำเตือนเกี่ยวกับเอาต์พุตของคอมไพเลอร์) ซึ่งมีการประเมินมาโคร
Florian Castellane

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>นี้จะถูกตีความโดย preprocesor เป็นผ่าน 2 ข้อโต้แย้งไปยังแมโครเลิกใช้ ในกรณีนั้นคุณจะต้องพิมพ์ประเภทผลตอบแทน

แก้ไข: ง่าย ( แต่อาจเป็นไปได้น้อยที่เข้ากันได้อย่างกว้างขวาง) รุ่นที่นี่


6
แทนที่จะ #error จะเป็นการดีกว่าหาก #define เลิกใช้งาน (func) func
CesarB

1
mxp: การคัดค้านเป็นเพียงคำเตือนและด้วยเหตุนี้ฉันจึงบอกว่าคำเตือนที่ไม่ได้รับการสนับสนุนคือสิ่งที่คุณต้องการ
Leon Timmermans

1
ใช่ฉันจะไปที่ "#warning คุณต้องติดตั้ง DEPRECATED สำหรับคอมไพเลอร์นี้" หรือบางอย่าง หากนั่นเป็นไปไม่ได้พนักงานยกกระเป๋าสามารถ #define DEPRECATED (FUNC) FUNC และใช้ชีวิตโดยปราศจากมัน
Steve Jessop

2
น่าเสียดายที่ไม่มีวิธีมาตรฐานในการแสดงผลคำเตือนการคอมไพล์ในข้อความ C ++: P #pragma
Michael Platings

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
ฉันไม่เห็นความแตกต่างอย่างมีนัยสำคัญระหว่างคำตอบทั้งสองนั้น ทำไมคุณถึงโพสต์มันเป็นครั้งที่สอง?
Tomáš Zato - Reinstate Monica

4
คุณไม่จำเป็นต้องล้อมรอบฟังก์ชั่นดังนั้นจึงDEPRECATED void foo(...);แทนที่จะเป็นDEPRECATED(void foo(...));
dshepherd

12
คุณควรแก้ไขคำตอบปี 2551 ของคุณแทนที่จะโพสต์คำตอบใหม่
Yakov Galka

4
สิ่งนี้อาจไม่เข้ากันได้กับคำตอบอื่น ๆ ของฉันดังนั้นฉันจึงเพิ่มสิ่งนี้แยกต่างหาก
Michael Platings

22

ใน GCC คุณสามารถประกาศฟังก์ชั่นของคุณด้วยแอตทริบิวต์ที่เลิกใช้เช่นนี้:

void myfunc() __attribute__ ((deprecated));

สิ่งนี้จะทริกเกอร์การเตือนเวลาคอมไพล์เมื่อฟังก์ชันนั้นถูกใช้ในไฟล์. c

คุณสามารถค้นหาข้อมูลเพิ่มเติมภายใต้ "การวินิจฉัย pragmas" ได้ที่ http://gcc.gnu.org/onlinedocs/gcc/Pragmas.html


8

นี่คือคำตอบที่สมบูรณ์ยิ่งขึ้นสำหรับปี 2561

วันนี้มีเครื่องมือมากมายที่ช่วยให้คุณไม่เพียง แต่ทำเครื่องหมายว่าเลิกใช้แล้ว แต่ยังมีข้อความ วิธีนี้ช่วยให้คุณสามารถบอกผู้คนเมื่อมีบางสิ่งไม่เป็นที่ยอมรับ

ยังมีความหลากหลายในการรองรับคอมไพเลอร์:

  • 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 ++ Compiler กลับไปเป็นอย่างน้อย 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]]ในรุ่นที่ผ่านมาของเสียงดังกราวใน C ++ 11 __has_cpp_attribute(gnu::deprecated)ขึ้นอยู่กับ

ฉันมีมาโครบางตัวในHedleyเพื่อจัดการทั้งหมดนี้โดยอัตโนมัติซึ่งเป็นรุ่นล่าสุด แต่รุ่นปัจจุบัน (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มาโครหากคุณไม่ต้องการใช้ Hedley (ฉันเขียน Hedley เป็นส่วนใหญ่ดังนั้นฉันไม่ต้องคิดเรื่องนี้เป็นประจำ)

หากคุณใช้ GLib คุณสามารถใช้G_DEPRECATEDและG_DEPRECATED_FORมาโครได้ มันไม่แข็งแกร่งเท่า Hedley แต่ถ้าคุณใช้ GLib อยู่แล้วจะไม่มีอะไรเพิ่ม


4

การจัดการกับโปรเจ็กต์พกพาเป็นเรื่องที่หลีกเลี่ยงไม่ได้ที่คุณจะต้องมีส่วนของทางเลือกที่ประมวลผลล่วงหน้าแล้วสำหรับแพลตฟอร์มที่หลากหลาย #ifdef #ifdef นี้และอื่น ๆ

ในส่วนดังกล่าวคุณสามารถกำหนดวิธีในการตัดสัญลักษณ์ การตั้งค่าของฉันมักจะกำหนดมาโคร "คำเตือน" เนื่องจาก toolchains ส่วนใหญ่สนับสนุนคำเตือนคอมไพเลอร์ที่กำหนดเอง จากนั้นคุณสามารถใช้แมโครคำเตือนเฉพาะสำหรับการคัดค้านเป็นต้นสำหรับแพลตฟอร์มที่รองรับวิธีการคัดแยกเฉพาะคุณสามารถใช้วิธีนั้นแทนคำเตือน


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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.