c++ 命名空间别名踩坑
c++ 命名空间别名踩坑
遇到的问题
在现代c++以前(c++11), 实现别名的主要方式主要是通过typedef
关键字实现的.
今天写boost/asio
代码的时候, 遇到了这样的一个问题, 催生了我的这篇文章加深我的印象.
// 我想写boost.asio中的内容, 经常使用boost::asio::ip::xxxxxxx.
// 正是因为我是现代c++爱好者, 我使用using而不是typedef导入命名空间别名.
using asio = boost::asio;
// 诶? 报错了?
出现“命名空间 boost::asio 不能用作类型” 编译错误,因为 asio 是一个命名空间而不是一个类型。
如果想要使用asio::xxxxx
写, 你会选择什么样的解决方案呢?
我第一个想到的是
using namespace boost;
我当然可以直接使用asio::xxx
, 但是这正确吗? 我深知这样写肯定是不好的, 因为这样会导入整个boost命名空间, 会导致命名空间的一些名称产生冲突.
但是 using asio = boost::asio
编译不通过啊. 后来问了ChatGPT
老师, 得到了我需要的答案.
原来是这样解决的吗!
使用typedef
/using
只能够对类型生效. 对命名空间是不可以的!
正确的做法是 使用namespace
关键字
namespace asio = boost::asio;
不知道正在看文章的你们知不知道这样的写法, 反正当时的我是不知道可以使用namespace
关键字创建命名空间别名
的.
2024.8.19记 觉得又无奈又好笑, 基础知识不牢啊!!
回顾c++的别名系统
在C++中,别名的声明方式可以用于类型、命名空间和模板类型别名。以下是详细的介绍:
1. 类型别名
-
使用
typedef
typedef
是C语言和C++中早期的方式,用来为已有类型创建一个新的名字。
typedef unsigned long ulong; ulong a = 10;
-
使用
using
using
语法从C++11引入,是更现代化的一种类型别名声明方式,功能上与typedef
类似,但语法上更加直观,特别是在声明模板类型别名时。
using ulong = unsigned long; ulong a = 10;
2. 命名空间别名
- 可以为一个命名空间创建一个更短的别名。这对于长命名空间或者避免命名冲突很有帮助。
namespace asio = boost::asio;
asio::io_context io;
3. 模板类型别名
- C++11 之后,引入了使用
using
关键字来为模板类型创建别名。这比使用typedef
更加直观,因为using
支持更复杂的语法。
template<typename T>
using Vec = std::vector<T>;
Vec<int> v; // 等价于 std::vector<int> v;
- 使用
typedef
实现模板类型别名较为复杂,且难以阅读,因此using
通常是更好的选择。
4. 函数指针别名
- 可以为函数指针创建别名,方便在代码中使用。
使用 typedef
:
typedef void (*FuncPtr)(int);
void myFunction(int a) {}
FuncPtr fp = myFunction;
fp(10);
使用 using
:
using FuncPtr = void(*)(int);
void myFunction(int a) {}
FuncPtr fp = myFunction;
fp(10);
5. 嵌套的别名
- 别名可以嵌套使用,比如为某个复杂类型的某一部分创建别名。
using VecInt = std::vector<int>;
using VecIntIter = VecInt::iterator;
VecInt v = {1, 2, 3};
VecIntIter it = v.begin();
总结
typedef
主要用于早期C++代码和C语言中,但不支持模板类型别名的复杂语法。如果是为了适配C语言的代码,可以使用typedef。using
是C++11引入的,更加现代化和灵活,推荐在现代C++代码中使用。- 命名空间别名 和 模板类型别名 提供了更简洁和清晰的代码表达方式,特别适用于处理复杂类型和长命名空间。