CS106L(2): Types and Structs

Core Idea

Learn C++ Basic Types: structs(including Pair + Struct), Type Deduction with Auto, Structure Binding

Lecture 2 Types and Structs - Note

View Lecture Note


Namespaces provide a method for preventing name conflicts in large projects.

Symbols declared inside a namespace block are placed in a named scope that prevents them from being mistaken for identically-named symbols in other scopes.

Multiple namespace blocks with the same name are allowed. All declarations within those blocks are declared in the named scope.


namespace Q {
  namespace V { // V is a member of Q, and is fully defined within Q
// namespace Q::V { // C++17 alternative to the above two lines
    class C { void m(); }; // C is a member of V and is fully defined within V
                           // C::m is only declared
    void f(); // f is a member of V, but is only declared here
  void V::f() // definition of V's member f outside of V
              // f's enclosing namespaces are still the global namespace, Q, and Q::V
      extern void h(); // This declares ::Q::V::h
  void V::C::m() // definition of V::C::m outside of the namespace (and the class body)
                 // enclosing namespaces are the global namespace, Q, and Q::V

Lecture Note: using namespace std; is not a good type.

Recap: Types

C++ is a static-typed language. Need to define the type of a var when initialising.

static-type pros:

  • better performance
  • easier to understand
  • better error checking

common types: int, double, string, bool, size_t(size_t >=0)

To faster demo the examples in slide, use C++ online compiler, but it is too slow compared with command line.

Error on Lecture note page 13, // uses version (2), returns 15.0, should be 6.0 instead.


A struct is a group of named variables each with their own type, grouping information together when pass around or return.

Student DB:

struct Student {
	string name; // these are called fields
	string state; // separate these by semicolons
	int age;

Student s;
s.name = "Ethan"; // use the . operator to access fields
s.state = "CA";
s.age = 20;
// Student s = {“Ethan”, “CA”, 30};   //prefer this syntax

void printStudentInfo(Student student) {
	cout << student.name << " from " << student.state;
	cout << " (" << student.age ")" << endl;

// this lookupStudent function is a bit weird.
Student lookupStudent() {
	Student s;
	s.name = "Ethan";
	s.state = "CA";
	s.age = 20;
	return s;

Student foundStudent = lookupStudent();
cout << foundStudent.name << endl; 


A pair is a struct with two fields.

int main() {
	std::pair<bool, Student> query_result;
	query_result.first = true;
	Report current = query_result.second;

std::pair is a template.

Common use case: return success + result:

Student lookupStudent(string name) {
	Student blank;
	if (notFound(name)) return std::make_pair(false, blank);
	Student result = getStudentWithName(name);
	return std::make_pair(true, result);
std::pair<bool, Student> output = lookupStudent("Keith");

make_pair is a generic way to make a pair without explicitly writing a type


A tuple is a struct with lots of fields.

int main() {
	std::tuple<string, int, int> query_result;
	string name = std::get<1>(query_result);
	int num = std::get<2>(query_result);

std::tuple <- uncommon, will use std::vector more.

Live Code Demo: Quadratic.cpp

Have to say there are some errors in the lecture notes, here is the modified code:

#include <iostream>
#include <string>
#include <math.h>
#include <utility>      // std::pair, std::make_pair

std::pair<bool, std::pair<double, double>> quadratic (int a, int b, int c) {
	double inside = b*b - 4*a*c;
	std::pair<double, double> blank;
	if (inside < 0) return std::make_pair(false, blank);
	std::pair<double, double> answer = std::make_pair((-b+sqrt(inside))/2, (-b-sqrt(inside))/2);
	return std::make_pair(true, answer);

int main() {
	int a, b, c;
	std::cin >> a >> b >> c; // this gets input
	std::pair<bool, std::pair<double, double>> result = quadratic(a, b, c);
	if (result.first) {
		std::pair<double, double> solutions = result.second;
		std::cout << solutions.first << solutions.second << std::endl;
	} else {
		std::cout << "No solutions found!" << std::endl;


$ g++ quadratic.cpp -std=c++2a -g -Wall -o quadratic
$ ./quadratic

POC: poc c++

Type Deduction with Auto

auto does not mean that the variable doesn’t have a type. It means that the type is deduced by the compiler.


auto a = 3;
auto b = 4.3;
auto c = "X";
auto d = "Hello";
auto e = std::make_pair(3, "Hello");

Wrong Usage:

auto wrong(); // this won’t work
void wrong(string a, auto b) { // neither will this work
	return a * b;

Tips: Don’t overuse auto. Use auto to rescue long types, such as std::pair<bool, std::pair<double, double>>, std::pair<double, double>.

Structured Binding

Structured binding(Since C++17) lets you initialize directly from the contents of a struct. It works for pair & regular structs, no nested structured binding.


auto p = std::make_pair("s", 5);
string a = s.first;
int b = s.second;


auto p = std::make_pair("s", 5);
auto [a, b] = p;
// a is of type string
// b is of type int
// auto [a, b] = std::make_pair(...);

A better way to use quadratic

int main() {
	int a, b, c;
	std::cin >> a >> b >> c;
	auto [found, solutions] = quadratic(a, b, c);
	if (found) {
		auto [x1, x2] = solutions;
		std::cout << x1 << " " << x2 << endl;
	} else {
		std::cout << "No solutions found!" << endl;

From C++17 doc, A structured binding declaration then performs the binding in one of three possible ways, depending on E:

  • Case 1: if E is an array type, then the names are bound to the array elements.
  • Case 2: if E is a non-union class type and std::tuple_size is a complete type with a member named value (regardless of the type or accessibility of such member), then the “tuple-like” binding protocol is used.
  • Case 3: if E is a non-union class type but std::tuple_size is not a complete type, then the names are bound to the accessible data members of E.

Haha, congrats, second lecture finished!