第 18.3 節

using

0瀏覽次數0訪問次數--跳出率--平均停留

What problem does this section solve?

In C, we use typedef to create an alias for a type. However, the syntax of typedef is quite awkward, especially when aliasing function pointers or templates—the notation is unintuitive and hard to read.

C++11 introduced alias declarations, which have cleaner syntax and support template aliases, something the older feature typedef can't do.

What is this feature?

There are two common uses for using:

  1. Type Alias: Giving a new name to an existing type, similar to typedef but with clearer syntax.
  2. Template aliases: give alternate names to template types (which typedef cannot do).

C++ standard version

C++11 (type alias syntax), C++11 template aliases.

Required header files

No additional header files are required. using is a language keyword.

Basic Syntax

// 类型别名
using 新名字 = 已有类型;

// 模板别名
template<typename T>
using 新名字 = 模板类型<T...>;

Comparison with typedef

Scenetypedefusing
Primitive Typestypedef int Integer;using Integer = int;
function pointertypedef void (*Func)(int);using Func = void(*)(int);
arraytypedef int Arr10[10];using Arr10 = int[10];
Template Alias❌ Not supportedusing Vec<T> = std::vector<T>;

Using can do:

  • Simplify type names by creating aliases for namespaces and types.
  • Bring names from a base class into a derived class scope.

Using cannot do:

  • Replace the need for inheritance or virtual functions.
  • Change the fundamental behavior of a class or its methods.

using creates a type alias, not a new type. It improves the readability of complex types but doesn't prevent you from mistakenly using two types that are fundamentally the same underneath.

RequirementIs it suitable to useExplanation
Shorten complex type names✅ Suitableusing Callback = std::function<void(int)>;
Standardize business names in the project✅ Suitableusing UserId = int; make code more semantic
Simplified syntax for defining templates✅ Fits welltemplate<typename T> using Vec = std::vector<T>;
Preventing cross-contamination of different business types.Understood, the instructions are noted.using Meter = double; and using Second = double; are fundamentally still both doubles.
Create truly new typesUse struct / class / enum classThe compiler can help you check mixed use.

Example code

Example 1: using basics — replace 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;
}

Results

v1: 1 2 3 
v2: 4 5 6 

Example 2:Building on Example 1,using aliases for function pointers

#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;
}

Results

add(3, 5) = 8
multiply(3, 5) = 15

Example 3: Building on Example 2, template aliases (which typedef can't 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;
}

Results

Vec<int>: 1 2 3 
Vec<double>: 1.1 2.2 3.3 
StringMap<int>: Alice:85 Bob:92 

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;
}

Results

speed = 10.44
wrong order = 0.10
safe speed = 10.44

runtime results

See the "running results" for each example above.

Key syntax explanation in the example

|Here is the translation of the provided Simplified Chinese Markdown fragment into natural American English, following all specified rules.


ExampleDiscusses whatNewly emerged syntaxWhy write it this wayPrecautions
Example 1basic type aliasesusing Name = Type;The syntax is more intuitive, and the placeholder = makes it immediately clear that "alias = original type".Also works, but using is more readable.
Example 2function pointer aliasusing Func = int(*)(int,int);A name in the middle reads more naturally than a typedef name sandwiched in between.In actual projects, it is recommended to use std::function instead of raw function pointers.
Example 3Template Aliastemplate<T> using Vec = vector<T>;typedef cannot do template aliasing; this is a unique ability of using.Very suitable for simplifying nested template types
Example 4using is not a new typeusing Meter = double, packaging structureAliases enhance readability, structures ensure type safety.When parameter inversion needs to be prevented, do not rely solely on using.

Common Errors

Error 1: The = direction of the using alias is reversed

using int = MyInt;  // ❌ 方向反了!应该是 using 别名 = 原类型

Correct approach: using MyInt = int;

Error 2: Unrestricted use of using in header files

// 头文件中
using namespace std;  // ❌ 污染全局/外部命名空间!

Correct approach: avoid using namespace in header files; only use them in .cpp implementation files or within functions.

Error 3: Confusion between using declarations and using aliases

using std::cout;       // using 声明:引入名字
using MyVec = std::vector<int>;  // using 别名:创建别名

These represent two distinct usages: the former introduces a name into the current scope, while the latter creates a type alias.

错误 4:误以为 using 能提供强类型检查

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 a wrapper type like struct UserId { int value; }; or use enum class to express a limited set.

使用建议

  • 明确目标:在开始前确定您的具体需求,以便选择最合适的工具或教程。
  • 充分利用资源:参考官方文档、教程和博客,这些资料能帮助您快速上手并解决问题。
  • 实践应用:通过动手操作项目或编写代码来巩固学习成果,提升实际操作能力。
  • 问题解决:遇到困难时,查阅参考资料或寻求社区支持,逐步培养独立解决问题的能力。
  • 分享经验:完成项目后,可以撰写文章或博客分享心得,帮助其他学习者。

如果需要针对特定领域(如单片机、机器人或环境搭建)的进一步建议,请提供更多信息,我将为您细化内容。

  1. Replace using with typedef: The syntax is clearer and also supports template aliases.
  2. Leverage template aliases to simplify code: for example, using TaskMap = std::map<int, std::function<void()>>;.
  3. Do not use using namespace in header files: avoid namespace pollution.
  4. The using declaration (using std::cout) can be used in .cpp files or inside functions, simplifying the code.
  5. Don’t just use using when you need strong typing: while using improves readability, struct/class/enum class is what can change the type itself.

Summary

  • using NewName = OldType; is more intuitive than typedef in terms of syntax.
  • template<typename T> using Alias = ...; is a template alias that typedef cannot achieve.
  • Function pointer aliases and container type aliases are indeed practical in projects.
  • using is just an alias, not a new type; when type safety is required, you need to introduce wrapper types.
  • Don't confuse using aliases with using declarations (namespace introductions).
音乐页