內聯和巢狀名稱空間

iShare_爱分享發表於2024-04-14

在開發大型的專案時,往往會有很多人參與協同開發,劃分成各個小組負責不同的模組,模組之間相對獨立。程式碼中會定義很多的類名、函式名、模板名,甚至一些全域性變數,如果不對這些名稱加以規範,很容易造成名字的衝突,因為預設情況下這些名字都是全域性名字,這種情況也稱之為名稱空間汙染。為了避免這個問題,C++標準引入了名稱空間的概念,將不同模組的名字限定在各自模組的名稱空間中,名稱空間中的名字的作用域只在名稱空間內有效,儘可能地避免名字的衝突。名稱空間在C++98標準中已經引入,它的概念以及用法這裡就不再贅述,現在來介紹的是現代C++標準新增的功能:內聯名稱空間(C++11)和巢狀名稱空間(C++17),以及在C++20中的改進。

內聯名稱空間

C++11標準引入了內聯名稱空間的概念,它的語法就是在namespace前面加個inline關鍵字,如:

inline namespace MyCode {
    // source code
}

內聯名稱空間中的名字可以被上層名稱空間直接使用,也就是說,我們無需在內聯空間的名字前新增該名稱空間的名字為字首,透過上層名稱空間的名字就可以直接訪問他,如下:

namespace MyCode {
    namespace Lib_V1 {
        void foo() {}
    }
    inline namespace Lib_V2 {
        void foo() {}
    }
}

int main() {
	MyCode::Lib_V1::foo();
    MyCode::foo();
}

呼叫Lib_V1名稱空間的foo函式,前面需要加上Lib_V1的字首,而訪問Lib_V2名稱空間的foo函式則不需要。內聯名稱空間的作用之一是,當我們有一個模組,這個模組提供了一組介面供外部呼叫,有時我們需要升級介面以提供不同的功能,而新介面不與老介面相容,我們希望新寫的程式碼將呼叫我們提供的新介面,但是又不希望影響老的程式碼,所以老的介面需要保留。這時就可以使用內聯名稱空間的辦法來解決,就如上面的例子中,我們把新介面放在名稱空間Lib_V2中,並定義為內聯的名稱空間,使用者只需透過MyCode字首就可以訪問到它們,如:MyCode::foo(),老的程式碼的邏輯不需要改動,只需將原來呼叫介面的地方加個字首,如MyCode::Lib_V1::foo()。

內聯名稱空間在第一次定義時必須加上inline關鍵字,之後再重新開啟名稱空間時可以加上inline關鍵字,也可以不加上。

巢狀名稱空間

巢狀名稱空間在C++98中已有,如上節中的程式碼就定義了一個巢狀名稱空間,但它的寫法比較冗餘,如果要定義多重的巢狀則顯得更加冗餘,特別是在程式碼縮排時,比如:

namespace A {
    namespace B {
        namespace C {
            void foo() {}
        }
    }
}

訪問foo函式時透過A::B::C::foo()來呼叫,如果定義名稱空間時也可以像這樣的話程式碼將會變得更加簡潔,因此C++17標準中引入了更簡潔的巢狀名稱空間的定義方式,如:

namespace A::B::C {
    void foo() {}
}

這樣程式碼就顯得簡潔得多,它也更符合我們的使用習慣。當遺憾的是,在C++17中沒有解決在巢狀名稱空間中定義內聯名稱空間,也就是說在上面的巢狀名稱空間中沒法加入inline關鍵字,使得子名稱空間成為內聯的,直到C++20標準中完善了這個功能。因此在C++20中,我們可以透過以下的方式來定義名稱空間:

namespace A::B::inline C {
    void foo() {}
}
// 它等同於如下定義:
namespace A::B {
    inline namespace C {
    	void foo() {}
    }
}
// 呼叫foo函式:
A::B::foo();

// 或者也可以這樣定義:
namespace A::inline B::C {
    void foo() {}
}
// 它等同於如下定義:
namespace A {
    inline namespace B {
        namespace C {
            void foo() {}
        }
    }
}
// 呼叫foo函式:
A::C::foo();

需要注意的是,inline關鍵字可以出現在除第一個namespace之外的任意namespace之前,上面的程式碼需要使用支援C++20標準的編譯器來編譯,在編譯時加上引數-std=c++20。

此篇文章同步釋出於我的微信公眾號:內聯和巢狀名稱空間

如果您感興趣這方面的內容,請在微信上搜尋公眾號iShare愛分享或者微訊號iTechShare並關注,或者掃描以下二維碼關注,以便在內容更新時直接向您推送。
image

相關文章