上一篇:《深入理解C++11》笔记-用户自定义字面量
名字空间或者是命名空间,大家应该都有所了解,最常用的就是C++标准的std名字空间。名字空间的作用是区别同名的全局成员,例如在两个头文件中声明了同名的函数,如果在其他地方同时包含了两个头文件,编译时就会报错。
// test1.h
void func();
// test1.cpp
void func(){}
// test2.h
void func();
// test2.cpp
void func(){}
而通过名字空间可以解决这个问题:
// test1.h
namespace A{
void func();
}
// test1.cpp
namespace A{
void func(){}
}
// test2.h
namespace A{
void func();
}
// test2.cpp
namespace A{
void func(){}
}
这样就能区分两个版本的同名函数,不过在使用的时候需要通过A::func()或者B::func()来调用,或者在使用前通过using A获取中using B打开名字空间然后直接调用函数。
名字空间能够有效分割不同的功能或模块,但是也会引起一些问题。例如名字空间的嵌套使用,在名字空间外部需要声明多个名字空间。
namespace NameA {
namespace NameB {
struct Example {};
}
namespace NameC {
Example ex; // 无法通过编译
NameB::Example ex; // 加上名字空间后能够编译通过
}
}
int main()
{
NameA::NameB::Example ex;
return 0;
}
或者在NameA中通过using打开名字空间,这样外部调用只需要知道NameA名字空间。
namespace NameA {
namespace NameB {
struct Example {};
}
namespace NameC {
}
using namespace NameB;
}
int main()
{
NameA::Example ex;
return 0;
}
C++11当中引入了内联名字空间的特性,内联名字控件可以让不同名字空间之间相互访问,但是这样会破坏名字空间的分割性:
namespace NameA {
inline namespace NameB { // 声明为inline
struct Example {};
}
inline namespace NameC { // 声明为inline
template<typename T> class Class {};
Example exC; // 不用打开名字空间NameB也能使用
}
}
namespace NameA {
template<> class Class<Example> {}; // 使用内联名字空间还能在不打开名字空间的情况下,进行模板特化(否则会编译失败)
}
using namespace NameA;
int main()
{
Example ex; // 不用打开名字空间NameB也能使用
Class<Example> classEx;
return 0;
}
这种用法通常用来实现根据编译器支持的C++版本调用不同代码:
namespace NameA {
#if __cplusplus == 201103L
inline
#endif // __cplusplus
namespace cpp11 {
struct Example {};
}
#if __cplusplus < 201103L
inline
#endif // __cplusplus
namespace cppold {
struct Example {};
}
}
using namespace NameA;
int main()
{
Example ex; // 根据编译器的C++版本默认选择inline版本
cppold::Example ex;
cpp11::Example ex;
return 0;
}