Using C++¶
- Lecture 11 will cover the baiscs of C++ progamming.
- Lecture 12 will cover how to call C++ libraries from Python using
pybind11
Since we are mainly learning C++ to wrap for use in Python, we will ignore C++ I/O.
The compilation process¶
Hello, world¶
%mkdir hello
%cd hello
mkdir: hello: File exists
/Users/cliburn/git-teach/sta-663-2017-public/scratch/hello
%%file hello.cpp
#include <iostream>
using std::cout;
using std::endl;
int main() {
cout << "Hello, world" << endl;
}
Overwriting hello.cpp
! g++ hello.cpp -o hello
! ./hello
Hello, world
%cd ..
/Users/cliburn/git-teach/sta-663-2017-public/scratch
A simple function¶
%mkdir add1
%cd add1
mkdir: add1: File exists
/Users/cliburn/git-teach/sta-663-2017-public/scratch/add1
%%file add.cpp
#include <iostream>
using std::cout;
using std::endl;
double add(double a, double b) {
return a + b;
}
int main() {
double a = 1.0, b= 2.0;
double c = add(a, b);
cout << a << " + " << b << " = " << c << endl;
}
Overwriting add.cpp
! g++ add.cpp -o add
! ./add
1 + 2 = 3
%cd ..
/Users/cliburn/git-teach/sta-663-2017-public/scratch
Using header files¶
%mkdir add2
%cd add2
mkdir: add2: File exists
/Users/cliburn/git-teach/sta-663-2017-public/scratch/add2
%%file add.hpp
#pragma once
double add(double a, double b);
Overwriting add.hpp
%%file add.cpp
double add(double a, double b) {
return a + b;
}
Overwriting add.cpp
%%file add_driver.cpp
#include "add.hpp"
#include <iostream>
using std::cout;
using std::endl;
int main() {
double a = 1.0, b = 2.0;
double c = add(a, b);
cout << a << " + " << b << " = " << c << endl;
}
Overwriting add_driver.cpp
%%bash
g++ add_driver.cpp add.cpp -o add_driver
./add_driver
1 + 2 = 3
%cd ..
/Users/cliburn/git-teach/sta-663-2017-public/scratch
Notes:¶
#pragma once
is non-standard but very widely supported- if you want to be pedantic, use traditional guards
%%file src/add.hpp
#ifndef ADD_HPP
#define ADD_HPP
double add(double a, double b);
#endif /* ADD_HPP */
Using make
¶
%mkdir add3
%cp add2/add.cpp add2/add.hpp add2/add_driver.cpp add3/
%cd add3
mkdir: add3: File exists
/Users/cliburn/git-teach/sta-663-2017-public/scratch/add3
%%file Makefile
add_driver: add_driver.o add.o
g++ add_driver.o add.o -o add_driver
add_driver.o: add_driver.cpp add.hpp
g++ -c add_driver.cpp
add.o: add.cpp
g++ -c add.cpp
.PHONY: clean
clean:
rm add_driver *.o
Overwriting Makefile
! make
g++ -c add_driver.cpp
g++ -c add.cpp
g++ add_driver.o add.o -o add_driver
! make clean
rm add_driver *.o
! make
g++ -c add_driver.cpp
g++ -c add.cpp
g++ add_driver.o add.o -o add_driver
A reusable Makefile¶
%%file Makefile
# Declaration of variables
CC = g++
CC_FLAGS = -Wall -std=c++11
# File names
EXEC = add_driver
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)
# Main target
$(EXEC): $(OBJECTS)
$(CC) $(OBJECTS) -o $(EXEC)
# To obtain object files
%.o: %.cpp
$(CC) -c $(CC_FLAGS) $< -o $@
# To remove generated files
clean:
rm -f $(EXEC) $(OBJECTS)
Overwriting Makefile
%%bash
make clean
make
./add_driver
rm -f add_driver add.o add_driver.o
g++ -c -Wall -std=c++11 add.cpp -o add.o
g++ -c -Wall -std=c++11 add_driver.cpp -o add_driver.o
g++ add.o add_driver.o -o add_driver
1 + 2 = 3
%cd ..
/Users/cliburn/git-teach/sta-663-2017-public/scratch
Linking to a library¶
%mkdir linker
%cd linker
mkdir: linker: File exists
/Users/cliburn/git-teach/sta-663-2017-public/scratch/linker
%%file test_linker.cpp
#include <cmath>
#include <iostream>
using std::cout;
using std::endl;
int main() {
cout << "2^10 = " << pow(2, 10) << endl;
}
Overwriting test_linker.cpp
%%file Makefile
# Declaration of variables
CC = g++
CC_FLAGS = -Wall -std=c++11
# File names
EXEC = test_linker
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)
# Main target
$(EXEC): $(OBJECTS)
$(CC) $(OBJECTS) -o $(EXEC)
# To obtain object files
%.o: %.cpp
$(CC) -c $(CC_FLAGS) $< -o $@
# To remove generated files
clean:
rm -f $(EXEC) $(OBJECTS)
Overwriting Makefile
! make
g++ -c -Wall -std=c++11 test_linker.cpp -o test_linker.o
g++ test_linker.o -o test_linker
! ./test_linker
2^10 = 1024
%cd ..
/Users/cliburn/git-teach/sta-663-2017-public/scratch
Arrays, pointers and dereferencing¶
%mkdir arrays
%cd arrays
mkdir: arrays: File exists
[Errno 20] Not a directory: 'arrays'
/Users/cliburn/git-teach/sta-663-2017-public/scratch
%%file arrays.cpp
#include <cmath>
#include <iostream>
using std::cout;
using std::endl;
int main() {
// pointers and address-of opertor
int a = 1, b = 2;
int *p = &a, *q = &b;
cout << a << ", " << b << endl;
cout << *p << ", " << *q << endl;
cout << p << ", " << q << endl;
// An array name is just a pointer
int ms[] = {1,2,3,4};
// using indexing
cout << ms[0] << ", " << ms[1] << endl;
// using pointer arithmetic
cout << *(ms) << ", " << *(ms + 0) << ", " << *(ms + 2) << endl;
cout << 2[ms] << ", " << 3[ms] << endl; // wait, what??
// size of an array
cout << sizeof(ms)/sizeof(*ms) << endl;
}
Overwriting arrays.cpp
%%file Makefile
# Declaration of variables
CC = g++
CC_FLAGS = -Wall -std=c++11
# File names
EXEC = arrays
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)
# Main target
$(EXEC): $(OBJECTS)
$(CC) $(OBJECTS) -o $(EXEC)
# To obtain object files
%.o: %.cpp
$(CC) -c $(CC_FLAGS) $< -o $@
# To remove generated files
clean:
rm -f $(EXEC) $(OBJECTS)
Overwriting Makefile
%%bash
make
./arrays
g++ -c -Wall -std=c++11 arrays.cpp -o arrays.o
g++ arrays.o -o arrays
1, 2
1, 2
0x7fff56a6b4fc, 0x7fff56a6b4f8
1, 2
1, 1, 3
3, 4
4
%cd ..
/Users/cliburn/git-teach/sta-663-2017-public
Loops in C++¶
%mkdir loops
%cd loops
mkdir: loops: File exists
/Users/cliburn/git-teach/sta-663-2017-public/loops
%%file loops.cpp
#include <cmath>
#include <iostream>
using std::cout;
using std::endl;
int main() {
double xs[] = {0,1,2,3,4,5,6,7,8,9};
// looping with an index
for (int i=0; i<sizeof(xs)/sizeof(*xs); i++) {
cout << pow(xs[i], 2) << " ";
}
cout << endl;
// looping with an iterator
for (auto it=std::begin(xs); it!=std::end(xs); it++) {
cout << pow(*it, 2) << " ";
}
cout << endl;
// ranged for loop
for (auto x : xs) {
cout << pow(x, 2) << " ";
}
cout << endl;
}
Overwriting loops.cpp
%%file Makefile
# Declaration of variables
CC = g++
CC_FLAGS = -Wall -std=c++11
# File names
EXEC = loops
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)
# Main target
$(EXEC): $(OBJECTS)
$(CC) $(OBJECTS) -o $(EXEC)
# To obtain object files
%.o: %.cpp
$(CC) -c $(CC_FLAGS) $< -o $@
# To remove generated files
clean:
rm -f $(EXEC) $(OBJECTS)
Overwriting Makefile
%%bash
make clean
make
./loops
rm -f loops loops.o
g++ -c -Wall -std=c++11 loops.cpp -o loops.o
g++ loops.o -o loops
0 1 4 9 16 25 36 49 64 81
0 1 4 9 16 25 36 49 64 81
0 1 4 9 16 25 36 49 64 81
%cd ..
/Users/cliburn/git-teach/sta-663-2017-public
Functions in C++¶
%mkdir funcs1
%cd funcs1
mkdir: funcs1: File exists
/Users/cliburn/git-teach/sta-663-2017-public/funcs1
%%file funcs1.cpp
#include <iostream>
using std::cout;
using std::endl;
double sum(double *xs, int n) {
double s = 0.0;
for (int i=0; i<n; i++) {
s += xs[i];
}
return s;
}
void triple(double *xs, double * ys, int n) {
for (int i=0; i<n; i++) {
ys[i] = 3 * xs[i];
}
}
int main() {
double xs[] = {1,2,3,4};
int n = sizeof(xs)/sizeof(*xs);
cout << sum(xs, n) << endl;
double ys[n];
triple(xs, ys, n);
for (auto y : ys) {
cout << y << " ";
}
cout << endl;
}
Overwriting funcs1.cpp
%%file Makefile
# Declaration of variables
CC = g++
CC_FLAGS = -Wall -std=c++11
# File names
EXEC = funcs1
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)
# Main target
$(EXEC): $(OBJECTS)
$(CC) $(OBJECTS) -o $(EXEC)
# To obtain object files
%.o: %.cpp
$(CC) -c $(CC_FLAGS) $< -o $@
# To remove generated files
clean:
rm -f $(EXEC) $(OBJECTS)
Overwriting Makefile
%%bash
make
./funcs1
g++ -c -Wall -std=c++11 funcs1.cpp -o funcs1.o
g++ funcs1.o -o funcs1
10
3 6 9 12
%cd ..
/Users/cliburn/git-teach/sta-663-2017-public
Anonymous functions¶
%mkdir funcs2
%cd funcs2
mkdir: funcs2: File exists
[Errno 20] Not a directory: 'funcs2'
/Users/cliburn/git-teach/sta-663-2017-public
%%file funcs2.cpp
#include <iostream>
using std::cout;
using std::endl;
int main() {
double k = 5.0;
double a = 1.0, b = 2.0;
auto add1 = [](int a, int b) { return a + b; };
auto add2 = [k](int a, int b) { return a + b + k; };
auto add3 = [&k](int a, int b) { return a + b + k; };
k *= 2;
cout << "Lambda: " << add1(a, b) << endl;
cout << "Lambda with capture by value: " << add2(a, b) << endl;
cout << "Lmabda with capture by reference: " << add3(a, b) << endl;
}
Overwriting funcs2.cpp
%%file Makefile
# Declaration of variables
CC = g++
CC_FLAGS = -Wall -std=c++11
# File names
EXEC = funcs2
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)
# Main target
$(EXEC): $(OBJECTS)
$(CC) $(OBJECTS) -o $(EXEC)
# To obtain object files
%.o: %.cpp
$(CC) -c $(CC_FLAGS) $< -o $@
# To remove generated files
clean:
rm -f $(EXEC) $(OBJECTS)
Overwriting Makefile
%%bash
make clean
make
./funcs2
rm -f funcs2 funcs2.o
g++ -c -Wall -std=c++11 funcs2.cpp -o funcs2.o
g++ funcs2.o -o funcs2
Lambda: 3
Lambda with capture by value: 8
Lmabda with capture by reference: 13
%cd ..
/Users/cliburn/git-teach
Templates¶
%mkdir templates
%cd templates
mkdir: templates: File exists
/Users/cliburn/git-teach/templates
%%file templates.cpp
#include <iostream>
#include <vector>
#include <list>
#include <numeric>
using std::cout;
using std::endl;
using std::list;
using std::vector;
template<typename T>
T sum(vector<T> xs) {
T s = 0.0;
for (auto x : xs) {
s += x;
}
return s;
}
int main(){
vector<int> ns = {1,2,3};
vector<double> xs = {4.5, 6.4, 7.8};
// sum works with integers
cout << "Sum of ints: " << sum(ns) << endl;
// sum works with doubles
cout << "Sum of doubles: " << sum(xs) << endl;
// iota from the numeric library behaves like range
list<int> ys(10);
std::iota(ys.begin(), ys.end(), -3);
// accumulate from the numeric library behavses like reduce with default operation of addition
cout << "Sum from iota: " << std::accumulate(ys.begin(), ys.end(), 6.0) << endl;
// Note that the initial value determines the template type
cout << "Sum of doubles using accumulate: " << std::accumulate(xs.begin(), xs.end(), 0.0) << endl;
cout << "Surpise: " << std::accumulate(xs.begin(), xs.end(), 0) << endl;
// The binary operation can be user-defined
auto op = std::multiplies<int>();
cout << "Product of ints: " << std::accumulate(ns.begin(), ns.end(), 1, op) << endl;
}
Overwriting templates.cpp
%%file Makefile
# Declaration of variables
CC = g++
CC_FLAGS = -Wall -std=c++11
# File names
EXEC = templates
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)
# Main target
$(EXEC): $(OBJECTS)
$(CC) $(OBJECTS) -o $(EXEC)
# To obtain object files
%.o: %.cpp
$(CC) -c $(CC_FLAGS) $< -o $@
# To remove generated files
clean:
rm -f $(EXEC) $(OBJECTS)
Overwriting Makefile
%%bash
make clean
make
./templates
rm -f templates templates.o
g++ -c -Wall -std=c++11 templates.cpp -o templates.o
g++ templates.o -o templates
Sum of ints: 6
Sum of doubles: 18.7
Sum from iota: 21
Sum of doubles using accumulate: 18.7
Surpise: 17
Product of ints: 6
%cd ..
/Users/cliburn/git-teach
Function pointers¶
%mkdir func_ptrs
%cd func_ptrs
mkdir: func_ptrs: File exists
/Users/cliburn/git-teach/func_ptrs
%%file func_ptrs.cpp
#include <numeric>
#include <functional>
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
double sum(vector<double> xs) {
return std::accumulate(xs.begin(), xs.end(), 0.0);
}
double prod(vector<double> xs) {
return std::accumulate(xs.begin(), xs.end(), 1.0, std::multiplies<double>());
}
// funciton pointers in C++ are easy
using func = std::function<double(double)>;
// now you can pass in a funciton as an argument
double mystery(double x, func f) {
return f(x);
}
double foo(double x) {
return 2*x + 1;
}
double bar(double x) {
return 42*x;
}
int main() {
vector<double> xs = {1.2, 2.3};
cout << sum(xs) << endl;
cout << prod(xs) << endl;
// auto can crate iterables of functions!
auto funcs = {sum, prod};
for (auto f: funcs) {
cout << f(xs) << endl;
}
int x = 2;
cout << mystery(x, foo) << endl;
cout << mystery(x, bar) << endl;
cout << mystery(x, [](double x) {return x*x;}) << endl;
}
Overwriting func_ptrs.cpp
%%file Makefile
# Declaration of variables
CC = g++
CC_FLAGS = -Wall -std=c++11
# File names
EXEC = func_ptrs
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)
# Main target
$(EXEC): $(OBJECTS)
$(CC) $(OBJECTS) -o $(EXEC)
# To obtain object files
%.o: %.cpp
$(CC) -c $(CC_FLAGS) $< -o $@
# To remove generated files
clean:
rm -f $(EXEC) $(OBJECTS)
Overwriting Makefile
%%bash
make clean
make
./func_ptrs
rm -f func_ptrs func_ptrs.o
g++ -c -Wall -std=c++11 func_ptrs.cpp -o func_ptrs.o
g++ func_ptrs.o -o func_ptrs
3.5
2.76
3.5
2.76
5
84
4
%cd ..
/Users/cliburn/git-teach
Using a numeric library¶
We show the Armadillo numeric library here; in the next lecture, we will show the competing Eigen libary.
%mkdir numeric
%cd numeric
mkdir: numeric: File exists
/Users/cliburn/git-teach/numeric
%%file numeric.cpp
#include <iostream>
#include <fstream>
#include <armadillo>
using std::cout;
using std::ofstream;
int main()
{
using namespace arma;
vec u = linspace<vec>(0,1,5);
vec v = ones<vec>(5);
mat A = randu<mat>(4,5); // uniform random deviates
mat B = randn<mat>(4,5); // normal random deviates
cout << "\nVecotrs in Armadillo\n";
cout << u << endl;
cout << v << endl;
cout << u.t() * v << endl;
cout << "\nRandom matrices in Armadillo\n";
cout << A << endl;
cout << B << endl;
cout << A * B.t() << endl;
cout << A * v << endl;
cout << "\nQR in Armadillo\n";
mat Q, R;
qr(Q, R, A.t() * A);
cout << Q << endl;
cout << R << endl;
}
Overwriting numeric.cpp
%%file Makefile
# Declaration of variables
CC = g++
CC_FLAGS = -Wall -std=c++11
LD_FLAGS = -larmadillo # Add library for linking
# File names
EXEC = numeric
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)
# Main target
$(EXEC): $(OBJECTS)
$(CC) $(LD_FLAGS) $(OBJECTS) -o $(EXEC)
# To obtain object files
%.o: %.cpp
$(CC) -c $(CC_FLAGS) $< -o $@
# To remove generated files
clean:
rm -f $(EXEC) $(OBJECTS)
Overwriting Makefile
%%bash
make clean
make
./numeric
rm -f numeric numeric.o
g++ -c -Wall -std=c++11 numeric.cpp -o numeric.o
g++ -larmadillo numeric.o -o numeric
Vecotrs in Armadillo
0
0.2500
0.5000
0.7500
1.0000
1.0000
1.0000
1.0000
1.0000
1.0000
2.5000
Random matrices in Armadillo
7.8264e-06 5.3277e-01 6.7930e-01 8.3097e-01 6.7115e-01
1.3154e-01 2.1896e-01 9.3469e-01 3.4572e-02 7.6982e-03
7.5561e-01 4.7045e-02 3.8350e-01 5.3462e-02 3.8342e-01
4.5865e-01 6.7886e-01 5.1942e-01 5.2970e-01 6.6842e-02
-0.7649 1.2041 -0.7020 1.1862 0.8284
1.7313 0.0937 1.6814 -0.8631 0.9426
0.1454 -0.6920 0.2742 0.6810 0.2091
0.7032 0.2610 0.1752 1.3165 -0.5897
1.7063 1.1075 0.5238 0.9563
-0.4457 1.7973 0.1490 0.3544
-0.4095 2.2726 0.2990 0.4551
0.7857 1.3368 0.1140 1.2487
2.7142
1.3275
1.6230
2.2535
QR in Armadillo
-0.6776 0.6377 0.3253 0.0944 -0.1395
-0.3188 -0.4409 0.3521 0.4177 0.6368
-0.5524 -0.2366 -0.7774 0.1504 -0.1092
-0.2443 -0.5816 0.4071 -0.1709 -0.6380
-0.2727 -0.0688 -0.0099 -0.8745 0.3950
-1.1785e+00 -1.3394e+00 -2.1015e+00 -1.3527e+00 -1.0229e+00
0e+00 -8.3421e-01 -9.7607e-01 -9.9515e-01 -5.3245e-01
0e+00 0e+00 -4.6336e-01 7.6793e-02 -4.0376e-03
0e+00 0e+00 0e+00 -2.0273e-01 -3.2745e-01
0e+00 0e+00 0e+00 0e+00 1.1102e-16
%cd ..
/Users/cliburn/git-teach