namespace Inline là một thư viện phiên bản tính năng tương tự như symbol versioning, nhưng thực hiện hoàn toàn ở cấp C++ 11 (tức. Cross-platform) thay vì là một tính năng của một định dạng thực thi nhị phân cụ thể (nền tảng cụ thể ví dụ.) . Đây là một cơ chế mà tác giả thư viện có thể tạo ra một không gian tên lồng nhau và hành động như thể tất cả các khai báo của nó nằm trong không gian tên xung quanh (các không gian tên nội tuyến có thể được lồng nhau, do đó, các tên "lồng nhau" sẽ tăng lên tất cả các cách đến không gian tên không nội tuyến đầu tiên và xem và hành động như thể các khai báo của chúng cũng nằm trong bất kỳ không gian tên nào ở giữa).
Ví dụ: xem xét việc triển khai STL của vector
. Nếu chúng ta có không gian tên inline từ đầu C++, sau đó trong C++ 98 header <vector>
có thể trông như thế này:
namespace std {
#if __cplusplus < 1997L // pre-standard C++
inline
#endif
namespace pre_cxx_1997 {
template <class T> __vector_impl; // implementation class
template <class T> // e.g. w/o allocator argument
class vector : __vector_impl<T> { // private inheritance
// ...
};
}
#if __cplusplus >= 1997L // C++98/03 or later
// (ifdef'ed out b/c it probably uses new language
// features that a pre-C++98 compiler would choke on)
# if __cplusplus == 1997L // C++98/03
inline
# endif
namespace cxx_1997 {
// std::vector now has an allocator argument
template <class T, class Alloc=std::allocator<T> >
class vector : pre_cxx_1997::__vector_impl<T> { // the old impl is still good
// ...
};
// and vector<bool> is special:
template <class Alloc=std::allocator<bool> >
class vector<bool> {
// ...
};
};
#endif // C++98/03 or later
} // namespace std
Tùy thuộc vào giá trị của __cplusplus
, một hoặc các vector
thi khác được chọn. Nếu codebase của bạn được viết bằng tiền C++ 98 lần, và bạn thấy rằng phiên bản C++ 98 của vector
gây rắc rối cho bạn khi bạn nâng cấp trình biên dịch, "tất cả" bạn phải làm là tìm các tham chiếu đến std::vector
trong codebase của bạn và thay thế chúng bằng std::pre_cxx_1997::vector
.
Hãy đến các tiêu chuẩn tiếp theo, và các nhà cung cấp STL chỉ lặp đi lặp lại các thủ tục một lần nữa, giới thiệu một không gian tên mới cho std::vector
với emplace_back
hỗ trợ (mà đòi hỏi C++ 11) và nội tuyến mà một khi và chỉ khi __cplusplus == 201103L
.
OK, vậy tại sao tôi cần một tính năng ngôn ngữ mới cho tính năng này? Tôi có thể làm như sau để có cùng tác dụng, phải không?
namespace std {
namespace pre_cxx_1997 {
// ...
}
#if __cplusplus < 1997L // pre-standard C++
using namespace pre_cxx_1997;
#endif
#if __cplusplus >= 1997L // C++98/03 or later
// (ifdef'ed out b/c it probably uses new language
// features that a pre-C++98 compiler would choke on)
namespace cxx_1997 {
// ...
};
# if __cplusplus == 1997L // C++98/03
using namespace cxx_1997;
# endif
#endif // C++98/03 or later
} // namespace std
Tùy thuộc vào giá trị của __cplusplus
, tôi nhận được một hoặc bên kia của hiện thực.
Và bạn sẽ gần như chính xác.
Hãy xem xét những điều sau C++ 98 mã người dùng hợp lệ (nó đã được phép chuyên đầy đủ mẫu mà sống trong không gian tên std
trong C++ 98 đã được):
// I don't trust my STL vendor to do this optimisation, so force these
// specializations myself:
namespace std {
template <>
class vector<MyType> : my_special_vector<MyType> {
// ...
};
template <>
class vector<MyOtherType> : my_special_vector<MyOtherType> {
// ...
};
// ...etc...
} // namespace std
này là hoàn toàn hợp lệ mã nơi người dùng cung cấp việc thực hiện của riêng mình một vectơ cho một tập hợp kiểu mà cô ấy dường như biết một cách thực hiện hiệu quả hơn so với cái được tìm thấy trong (bản sao của cô ấy) của STL.
Nhưng: Khi chuyên một mẫu, bạn cần phải làm như vậy trong không gian tên nó được khai báo trong Tiêu chuẩn nói rằng vector
được khai báo trong namespace std
, vì vậy đó là nơi người sử dụng chính đáng hy vọng sẽ chuyên các loại..
Mã này làm việc với một tổ chức phi phiên bản namespace std
, hoặc với các tính năng không gian tên inline C++ 11, nhưng không phải với các trick phiên bản được sử dụng using namespace <nested>
, bởi vì đó cho thấy nhiều chi tiết thực hiện mà không gian tên thật trong đó vector
là được xác định không trực tiếp là std
.
Có các lỗ khác mà bạn có thể phát hiện vùng tên lồng nhau (xem bình luận bên dưới), nhưng không gian tên nội tuyến cắm tất cả chúng. Và đó là tất cả để có nó. Vô cùng hữu ích cho tương lai, nhưng AFAIK Standard không quy định tên không gian tên nội tuyến cho thư viện chuẩn của riêng nó (mặc dù tôi đã được chứng minh là sai), vì vậy nó chỉ có thể được sử dụng cho các thư viện của bên thứ ba, chứ không phải bản thân tiêu chuẩn (trừ khi các nhà cung cấp trình biên dịch đồng ý về một lược đồ đặt tên).
+1 để giải thích lý do tại sao 'sử dụng không gian tên V99;' không hoạt động trong ví dụ của Stroustrup. –
Tôi cho rằng phiên bản trong thư viện chuẩn theo cách tiêu chuẩn, bị giới hạn so với phiên bản bên thứ 3.Nếu C++ 21 'vector' không tốt cho tôi, và tôi cần C++ 11' vectơ', thì điều đó có thể là do sự thay đổi đột ngột trong C++ 21. Nhưng có thể là do chi tiết triển khai mà tôi không nên dựa vào ngay từ đầu. Các tiêu chuẩn không thể yêu cầu rằng mỗi C + + 21 thực hiện cung cấp một 'std :: cxx_11 :: vector' đó là lỗi tương thích với bất kỳ quá khứ' std :: vector' từ cùng một nhà cung cấp. Thư viện của bên thứ ba có thể thực hiện điều đó, nếu họ nghĩ rằng nó đáng giá cho họ. –
Và tương tự, nếu tôi bắt đầu một triển khai C++ 21 hoàn toàn mới từ đầu, thì tôi không muốn bị gánh nặng khi thực hiện rất nhiều điều vô nghĩa cũ trong 'std :: cxx_11'. Không phải mọi trình biên dịch sẽ luôn luôn thực hiện tất cả các phiên bản cũ của các thư viện chuẩn, mặc dù nó hấp dẫn vào lúc này để nghĩ rằng nó sẽ rất ít gánh nặng để yêu cầu hiện thực để lại trong cũ khi họ thêm mới, vì thực tế tất cả chúng đều là anyway. Tôi cho rằng tiêu chuẩn có thể được thực hiện một cách hữu ích là tùy chọn, nhưng với một tên chuẩn nếu có. –