簡體   English   中英

C++ 中如何使用內聯說明符來保留一個定義規則?

[英]How is the inline specifier used in C++ to preserve the one definition rule?

我一直在試圖弄清楚inline說明符如何保留 ODR。 到目前為止,我寫的所有內容似乎都沒有必要,因為包含保護確保定義只包含一次。

假設我在名為constants.h的文件中有以下定義

#ifndef CONSTANTS_H
#define CONSTANTS_H

namespace constants {
    inline const double pi { 3.14159255358979323846 };
    inline const double e  { 2.71828182845904523536 };
}

#endif

根據我對與 ODR 相關的inline理解,編寫inline說明符是為了確保這些常量的定義僅在多個翻譯單元中初始化一次。 因此,如果我將這個文件包含在a.cppb.cpp一切都應該很好。

現在,讓我們刪除inline關鍵字。

#ifndef CONSTANTS_H
#define CONSTANTS_H

namespace constants {
    const double pi { 3.14159255358979323846 };
    const double e  { 2.71828182845904523536 };
}

#endif

現在,如果我將其包含在a.cppb.cpp沒有問題。 我想這是因為包含警衛確保同一事物的多個定義不會出現兩次。

接下來,讓我們移除包含守衛

namespace constants {
    const double pi { 3.14159255358979323846 };
    const double e  { 2.71828182845904523536 };
}

還是沒有問題。 可能是因為const限定的變量定義默認具有內部鏈接。 因此,在a.cppb.cpp包含constants.h使這些定義中的每一個都默認為各自的翻譯單元內部。

很難打破跨多個翻譯單元的 ODR。 現在讓我們刪除 const。

namespace constants {
    double pi { 3.14159255358979323846 };
    double e  { 2.71828182845904523536 };
}

現在! ODR 跨越多個翻譯單元。 讓我們嘗試使用inline修復此問題,以便編譯器知道只定義這些變量一次。

namespace constants {
    inline double pi { 3.14159255358979323846 };
    inline double e  { 2.71828182845904523536 };
}

好的,沒有更多錯誤,這個文件可以再次包含在多個翻譯單元中。 那么為什么將頭文件中的常量聲明為inline被認為是“最佳實踐”? 打破 ODR 似乎需要付出很多努力,並且在包含守衛的情況下inline是多余的。

未使用說明符 extern 聲明的常量具有內部鏈接。

所以所有包含這些聲明的編譯單元

namespace constants {
    const double pi { 3.14159255358979323846 };
    const double e  { 2.71828182845904523536 };
}

有自己的常數 pi 和 e。

來自 C++ 14 標准(3.5 程序和鏈接)

3 具有命名空間范圍 (3.3.6) 的名稱具有內部鏈接,如果它是

(3.2) — 非 volatile const 限定類型的變量,既未顯式聲明為 extern 也未先前聲明為具有外部鏈接; 或者

與上述聲明相反,這些聲明

namespace constants {
    double pi { 3.14159255358979323846 };
    double e  { 2.71828182845904523536 };
}

有外部聯動。 因此,如果這些聲明(也是定義)包含在多個編譯單元中,則編譯器會發出錯誤消息,因為一個定義規則被破壞。

例如,如果您在未命名的命名空間中聲明它們,則可以使上述變量具有內部鏈接

namespace constants {
    namespace {
        double pi { 3.14159255358979323846 };
        double e  { 2.71828182845904523536 };
    }
}

至於這些聲明

namespace constants {
    inline double pi { 3.14159255358979323846 };
    inline double e  { 2.71828182845904523536 };
}

然后可以在多個編譯單元中定義具有外部鏈接的內聯變量。 此外,應在每個使用 ODR 的編譯單元中定義內聯變量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM