Wiki
using
1.What problem does this section solve?
In C, use typedef to create type aliases. However, the syntax of typedef is very awkward, especially when creating aliases for function pointers and templates; the notation is unintuitive and hard to read.
C++11 introduced using alias declarations, with clearer syntax, and also supports template aliases (typedef could not do this).
2.What is this feature?
using There are two common uses:
- Type aliases : Give an existing type a new name, similar to
typedefbut with clearer syntax. - Template aliases : Give a template type an alias (
typedefcannot do this).
3.C++ Standard Edition
C++11 (type alias syntax), C++11 template alias.
4.Required header files
No additional header files are required.using is a language keyword.
5.Basic syntax
// 类型别名
using 新名字 = 已有类型;
// 模板别名
template<typename T>
using 新名字 = 模板类型<T...>;
6.Comparison with typedef
| Scenario | typedef | using |
|---|---|---|
| Primitive types | typedef int Integer; |
using Integer = int; |
| Function pointers | typedef void (*Func)(int); |
using Func = void(*)(int); |
| Arrays | typedef int Arr10[10]; |
using Arr10 = int[10]; |
| Template aliases | ❌ Not supported | using Vec<T> = std::vector<T>; |
7.What can be done with using, and what cannot be done
using creates atype aliasnot a new type. It can make complex types easier to read, but it cannot prevent you from mixing up two types with the same underlying type.
| Requirement | Is using suitable? | Description |
|---|---|---|
| Shorten complex type names | ✅ Suitable | using Callback = std::function<void(int)>; |
| Unify business names within a project | ✅ Suitable | using UserId = int; Make code more semantic |
| Simplified way to define templates | ✅ Very suitable | template<typename T> using Vec = std::vector<T>; |
| Prevent different business types from being passed incorrectly to each other | ❌ Not enough | using Meter = double; and using Second = double; are essentially both still double |
| Create a truly new type | Use struct / class / enum class |
Only then can the compiler help you check for mixing |
8.Example code
8.1.Example 1: using basics—replacing typedef
#include <iostream>
#include <string>
#include <vector>
// 旧写法(typedef)
typedef std::vector<int> IntVector1;
// 新写法(using)
using IntVector2 = std::vector<int>;
int main()
{
// 两种写法效果完全一样
IntVector1 v1 = {1, 2, 3};
IntVector2 v2 = {4, 5, 6};
std::cout << "v1: ";
for (int n : v1) std::cout << n << " ";
std::cout << "\n";
std::cout << "v2: ";
for (int n : v2) std::cout << n << " ";
std::cout << "\n";
return 0;
}
Running result:
v1: 1 2 3
v2: 4 5 6
8.2.Example 2: Based on Example 1, use using to create an alias for a function pointer
#include <iostream>
// typedef 的函数指针写法(别扭)
typedef int (*FuncPtr1)(int, int);
// using 的函数指针写法(直观)
using FuncPtr2 = int (*)(int, int);
int add(int a, int b)
{
return a + b;
}
int multiply(int a, int b)
{
return a * b;
}
int main()
{
FuncPtr2 op1 = add;
FuncPtr2 op2 = multiply;
std::cout << "add(3, 5) = " << op1(3, 5) << "\n";
std::cout << "multiply(3, 5) = " << op2(3, 5) << "\n";
return 0;
}
Running result:
add(3, 5) = 8
multiply(3, 5) = 15
8.3.Example 3: Building on Example 2, template aliases (which typedef cannot achieve)
#include <iostream>
#include <vector>
#include <map>
#include <string>
// 模板别名:定义一个泛型的 vector
template<typename T>
using Vec = std::vector<T>;
// 模板别名:键为 string 的 map
template<typename T>
using StringMap = std::map<std::string, T>;
int main()
{
Vec<int> vi = {1, 2, 3};
Vec<double> vd = {1.1, 2.2, 3.3};
StringMap<int> scores = {{"Alice", 85}, {"Bob", 92}};
std::cout << "Vec<int>: ";
for (int n : vi) std::cout << n << " ";
std::cout << "\n";
std::cout << "Vec<double>: ";
for (double d : vd) std::cout << d << " ";
std::cout << "\n";
std::cout << "StringMap<int>: ";
for (const auto& p : scores)
std::cout << p.first << ":" << p.second << " ";
std::cout << "\n";
return 0;
}
Running result:
Vec<int>: 1 2 3
Vec<double>: 1.1 2.2 3.3
StringMap<int>: Alice:85 Bob:92
8.4.Example 4: Building on Example 3, a using alias is not a new type
#include <iomanip>
#include <iostream>
using Meter = double;
using Second = double;
double speed(Meter distance, Second time)
{
return distance / time;
}
struct MeterValue
{
double value;
};
struct SecondValue
{
double value;
};
double safe_speed(MeterValue distance, SecondValue time)
{
return distance.value / time.value;
}
int main()
{
Meter distance = 100.0;
Second time = 9.58;
std::cout << std::fixed << std::setprecision(2);
std::cout << "speed = " << speed(distance, time) << "\n";
// using 只是别名,下面这行语义错了,但编译器仍然允许
std::cout << "wrong order = " << speed(time, distance) << "\n";
MeterValue d{100.0};
SecondValue t{9.58};
std::cout << "safe speed = " << safe_speed(d, t) << "\n";
// safe_speed(t, d); // ❌ 编译错误:SecondValue 不能当 MeterValue 用
return 0;
}
Running result:
speed = 10.44
wrong order = 0.10
safe speed = 10.44
9.Operation result
See the "run results" for each example above.
10.Key syntax explanation in the example
| Example | What was explained | Newly introduced syntax | Why it is written this way | Notes |
|---|---|---|---|---|
| Example 1 | Basic type alias | using Name = Type; |
The syntax is more intuitive,= making it clear at a glance that "alias = original type" |
typedef can also do this, but using is clearer |
| Example 2 | Function pointer alias | using Func = int(*)(int,int); |
The name is in the middle, which is easier to read than typedef where the name is sandwiched in the middle | In actual projects, it is recommended to use std::function instead of raw function pointers |
| Example 3 | Template alias | template<T> using Vec = vector<T>; |
typedef cannot do template aliases; this is a unique capability of using | Very suitable for simplifying nested template types |
| Example 4 | using is not a new type | using Meter = double、wrapper struct |
Aliases improve readability, structs provide type safety | When it is necessary to prevent arguments from being passed in the wrong order, do not rely only on using |
11.Common Errors
Error 1: Write the = direction of the using alias backwards
using int = MyInt; // ❌ 方向反了!应该是 using 别名 = 原类型
Correct approach:using MyInt = int;
Error 2: Unrestricted use of using in header files
// 头文件中
using namespace std; // ❌ 污染全局/外部命名空间!
Correct approach: avoid in header files using namespace, and use it only in the .cpp implementation file or inside functions.
Error 3: Confusing using declarations with using aliases
using std::cout; // using 声明:引入名字
using MyVec = std::vector<int>; // using 别名:创建别名
These are two different usages: the former introduces a name into the current scope, while the latter creates a type alias.
Mistake 4: Assuming that using can provide strong type checking
using UserId = int;
using ProductId = int;
void load_user(UserId id);
ProductId pid = 10;
load_user(pid); // 能编译,因为 UserId 和 ProductId 本质都是 int
Correct approach: If mixing must be prevented, use struct UserId { int value; }; this wrapper type, or use enum class to express a finite set.
12.Usage Recommendations
- Use
usinginstead oftypedef: the syntax is clearer and it also supports template aliases. - Make good use of template aliases to simplify code:For example
using TaskMap = std::map<int, std::function<void()>>;. - Do not use
using namespacein header files: avoid namespace pollution. - using declarations (
using std::cout) can be used in a .cpp file or inside a function to simplify code. - When strong typing is needed, do not rely only on using:using improves readability,
struct/class/enum classOnly then can the type itself be changed.
13.Summary
using NewName = OldType;Moretypedefintuitive than syntax.template<typename T> using Alias = ...;It is a template alias that typedef cannot achieve.- Function pointer aliases and container type aliases are very practical in projects.
usingIt is only an alias, not a new type; when type safety is needed, a wrapper type must be introduced.- Do not confuse the
usingalias and theusingdeclaration (namespace introduction).