C++ 基础(1):Types, Structs, Structured Bindings

4 min

在很多情况下(例如函数需要返回多个结果时),我们希望将多个相关的值组合为一个整体进行返回。C++ 提供了多种方式来对多个值进行建模与打包,例如使用 structstd::pairstd::tuple 将多个值组合成一个类型。在调用端,可以通过 structured binding 对这些聚合类型进行高效而清晰的解包,从而方便地获取各个返回值。

本文还简单介绍了几种初始化方法,以及推荐使用 uniform initialization {} 以禁止缩窄转换。

Types and Structs

Keywords.

  • Struct
  • Type alias
  • Auto type inference

Struct

  • build data together into a new, single object, thus
  • enable user to return multiple values simultaneously.
struct StanfordID {
    string name;
    string sunet;
    int idNumber;
};

StanfordID id;
id.name = "Jacob";
id.sunet = "jtrb";
id.idNumber = 6504417;

// -------------------
// Can now be returned
StanfordID issueNewID() {
    StanfordID id {"Jacob", "ad", 23};
    return id;
}

StanfordID new_id = issueNewID();

std::pair

std::pair is a general purpose struct with two fields.

std::pair<int, double> example {2, 3.14};
int first_num = example.first; // .first
double second_num =example.second; // .second

std::cout << example.first << std::endl;

std::tuple

std::tuple is a general purpose struct with multiple fields.

std::tuple<int, std::string, double> {2, "ad", 80.8};

Type alias and type inference

Type alias. using creates cd types alias and auto infers the type of a variable.

using Roots = std::pair<double, double>; // alias
using Solution = std::pair<bool, Roots>;

Automatic Type Inference. auto infers the type of a variable

std::map<std::string, std::vector<std::pair<int, std::unordered_map<char, double>>>> complexType;

auto it complexType.begin(); // auto = std::map<std::string, std::vector<std::pair<int, std::unordered_map<char, double>>>>::iterator

Initialization and Reference

Initialization

Methods of initialization.

  • Direct initialization: ()
    int numOne(12.0); // Direct initialization : doesn't care if 12.0 is a int or not
  • Uniform initialization (recommended!) : Care about types: {}
    int numTwo{12.0}; // Uniform initialization : DOES care, raise error

Structured binding

Structured Binding.

  • A useful way to initialize some variables from data structures with fixed sizes at compile time
  • Ability to access multiple values returned by a function
  • But! Can only use on objects where the size is known at compile time.

Example (Structured Binding).

NOTE

如何使用 Structured binding?

  • 在函数定义时,通常使用 struct 或 std::tuple<…> 作为返回类型,将多个值打包为一个整体;在函数体内,可以在 return 语句中直接使用 {…} 进行 uniform initialization。
  • 在调用函数的时候,直接 auto= [a, b, c] = f(); 进行返回参数解包为多个变量,同时避免拷贝开销

This is identical to use std::get<i>:

auto classInfo = getClassInfo();
std::string className = std::get<0>(classInfo);
std::string buildingName = std::get<1>(classInfo);
std::string language = std::get<2>(classInfo);

References

A reference is an alias to an already-existing thing.

int num = 5;
int& ref = num; // Reference

Example (Changing the value of the reference). The code ref = 10; will also change the value of num, the “referenced” value.

Pass by reference

Passing in a variable by reference: Take in the actual piece of memory, don’t make a copy!

// This function takes the actual piece of `nums` instead of modifing the COPY of `nums`
void shift(std::vector<std::pair<int, int>> &nums) {
    for (auto &num : nums) { // Common Bug
        std::swap(num.first, num.second);
    }
}

int main() {
    std::vector<std::pair<int, int>> nums {{2, 3}, {4, 5}};
    shift(nums);
    std::cout << nums[0].first << " " << nums[0].second << std::endl;
}

Common bug. With auto, structured bindings copy the element; add & to bind by reference.

// `auto` structured bindings copy;
// `auto&` binds by reference.
for (auto& [num1, num2] : nums) { ... }

L-values and R-values and reference

L-value

  • has stable identifiable location in memory, and
  • you can use it to modify the value stored at the location.

R-value is something that’s “manufactured on the spot”. It is temporary.

Example (R-value).

  • The return value of a function (which is not a reference): f()
  • Literal values 42

Only L-values can be passed by reference.

Const and reference

Can’t declare a non-const reference to a const variable

std::vector<int> vec{1, 2, 3};
const std::vector<int> const_vec{1, 2, 3};
const std::vector<int> &const_ref{vec};

// incorrect
std::vector<int> &invalid_ref{const_vec};