#include <vector>
template <typename T, typename Cont = std::vector<T>>
class Stack {
public:
Stack();
~Stack();
void push(T&);
void pop();
T& top();
const T& top() const;
static int numStacks_;
private:
Cont stack_;
};
template <typename T, typename Cont>
int Stack<T, Cont>::numStacks_ = 0;
template <typename T, typename Cont>
Stack<T, Cont>::Stack() { numStacks_++; }
template <typename T, typename Cont>
Stack<T, Cont>:: ~Stack() { numStacks_--; }
#include <iostream>
#include "lectures/week7/stack.h"
int main() {
Stack<float> fs;
Stack<int> is1, is2, is3;
std::cout << Stack<float>::numStacks_ << "\n";
std::cout << Stack<int>::numStacks_ << "\n";
}
#include <vector>
#include <iostream>
#include <numeric>
template <typename T>
class Stack {
public:
void push(T t) { stack_.push_back(t); }
T& top() { return stack_.back(); }
void pop() { stack_.pop_back(); }
int size() const { return stack_.size(); };
int sum() {
return std::accumulate(stack_.begin(), stack_.end(), 0);
}
private:
std::vector<T> stack_;
};
int main() {
int i1 = 6771;
int i2 = 1917;
Stack<int> s1;
s1.push(i1);
s1.push(i2);
std::cout << s1.size() << " ";
std::cout << s1.top() << " ";
std::cout << s1.sum() << "\n";
}
template <typename T>
class Stack<T*> {
public:
void push(T* t) { stack_.push_back(t); }
T* top() { return stack_.back(); }
void pop() { stack_.pop_back(); }
int size() const { return stack_.size(); };
int sum() {
return std::accumulate(stack_.begin(),
stack_.end(), 0, [] (int a, T *b) { return a + *b; });
}
private:
std::vector<T*> stack_;
};
int main() {
int i1 = 6771;
int i2 = 1917;
Stack<int*> s2;
s2.push(&i1);
s2.push(&i2);
std::cout << s2.size() << " ";
std::cout << *(s2.top()) << " ";
std::cout << s2.sum() << "\n";
}
#include <iostream>
template <typename T>
struct is_void {
static const bool val = false;
};
template<>
struct is_void<void> {
static const bool val = true;
};
int main() {
std::cout << is_void<int>::val << "\n";
std::cout << is_void<void>::val << "\n";
}
template <typename C>
void print_front(const C& c) {
std::cout << c.front() << "\n";
}
template <typename T>
void print_front(T* t) {
std::cout << *t << "\n";
}
What is the relationship between these two functions?
Not as trivial as you might think
template <typename C>
void print_front(const C& c) {
std::cout << c.front() << "\n";
}
template <typename T>
void print_front(T* t) {
std::cout << *t << "\n";
}
#include <iostream>
#include <limits>
int main() {
std::cout << std::numeric_limits<double>::min() << "\n";
std::cout << std::numeric_limits<int>::min() << "\n";
}
template <typename T>
struct numeric_limits {
static T min();
};
template <>
struct numeric_limits<int> {
static int min() { return -INT_MAX - 1; }
}
template <>
struct numeric_limits<float> {
static int min() { return -FLT_MAX - 1; }
}
This is what <limits> might look like
#include <array>
#include <iostream>
#include <limits>
template <typename T, unsigned long long size>
T findMax(const std::array<T, size>& arr) {
T largest = std::numeric_limits<T>::min();
for (const auto& i : arr) {
if (i > largest) largest = i;
}
return largest;
}
int main() {
std::array<int, 3> i{ -1, -2, -3 };
std::cout << findMax<int, 3>(i) << "\n";
std::array<double, 3> j{ 1.0, 1.1, 1.2 };
std::cout << findMax<double, 3>(j) << "\n";
}
#include <iostream>
template <typename T>
struct is_void {
static const bool val = false;
};
template<>
struct is_void<void> {
static const bool val = true;
};
int main() {
std::cout << is_void<int>::val << "\n";
std::cout << is_void<void>::val << "\n";
}
#include <iostream>
template <typename T>
struct is_pointer {
static const bool val = false;
};
template<typename T>
struct is_pointer<T*> {
static const bool val = true;
};
int main() {
std::cout << is_pointer<int*>::val << "\n";
std::cout << is_pointer<int>::val << "\n";
}
#include <iostream>
#include <type_traits>
template <typename T>
void testIfNumberType(T i) {
if (std::is_integral<T>::value || std::is_floating_point<T>::value) {
std::cout << i << " is a number" << "\n";
} else {
std::cout << i << " is not a number" << "\n";
}
}
int main() {
int i = 6;
long l = 7;
double d = 3.14;
testIfNumberType(i);
testIfNumberType(l);
testIfNumberType(d);
testIfNumberType(123);
testIfNumberType("Hello");
std::string s = "World";
testIfNumberType(s);
}
#include <iostream>
#include <typeinfo>
template <typename T>
void print(const T& msg) {
std::cout << msg << " ";
}
template <typename A, typename... B>
void print(A head, B... tail) {
print(head);
print(tail...);
}
int main() {
print(1, 2.0f);
std::cout << std::endl;
print(1, 2.0f, "Hello");
std::cout << std::endl;
}
void print(const char* const& c) {
std::cout << c << " ";
}
void print(const float& b) {
std::cout << b << " ";
}
void print(float b, const char* c) {
print(b);
print(c);
}
void print(const int& a) {
std::cout << a << " ";
}
void print(int a, float b, const char* c) {
print(a);
print(b, c);
}
#include <vector>
template <typename T>
class Stack {
public:
void push(T& t) { stack._push_back(t); }
T& top() { return stack_.back(); }
private:
std::vector<T> stack_;
};
int main() {
Stack<int> is1;
is1.push(2);
is1.push(3);
Stack<int> is2{is1}; // this works
Stack<double> ds1{is1}; // this does not
}
template <typename T>
class Stack {
public:
explicit Stack() {}
template <typename T2>
Stack(Stack<T2>&);
void push(T t) { stack_.push_back(t); }
T pop();
bool empty() const { return stack_.empty(); }
private:
std::vector<T> stack_;
};
template <typename T>
T Stack<T>::pop() {
T t = stack_.back();
stack_.pop_back();
return t;
}
template <typename T>
template <typename T2>
Stack<T>::Stack(Stack<T2>& s) {
while (!s.empty()) {
stack_.push_back(static_cast<T>(s.pop()));
}
}
int main() {
Stack<int> is1;
is1.push(2);
is1.push(3);
Stack<int> is2{is1}; // this works
Stack<double> ds1{is1}; // this does not
}
template <typename T, template <typename> Cont>
class stack {}
#include <iostream>
#include <vector>
int main(void) {
Stack<int, std::vector<int>> s1;
s1.push(1);
s1.push(2);
std::cout << "s1: " << s1 << std::endl;
Stack<float, std::vector<float>> s2;
s2.push(1.1);
s2.push(2.2);
std::cout << "s2: " << s2 << std::endl;
//Stack<float, std::vector<int>> s2; :O
}
Ideally we can just do:
#include <iostream>
#include <vector>
int main(void) {
Stack<int, std::vector> s1;
s1.push(1);
s1.push(2);
std::cout << "s1: " << s1 << std::endl;
Stack<float, std::vector> s2;
s2.push(1.1);
s2.push(2.2);
std::cout << "s2: " << s2 << std::endl;
}
#include <iostream>
#include <vector>
template <typename T, typename Cont>
class Stack {
public:
void push(T& t) { stack_.push_back(t); }
void pop() { stack_.pop_back(); }
T& top() { return stack_.back(); }
bool empty() const { return stack_.empty(); }
private:
Cont stack_;
};
#include <iostream>
#include <vector>
#include <memory>
template <typename T, template<typename, typename = std::allocator<T>> class Cont>
class Stack {
public:
void push(T t) { stack_.push_back(t); }
void pop() { stack_.pop_back(); }
T& top() { return stack_.back(); }
bool empty() const { return stack_.empty(); }
private:
Cont<T> stack_;
};
#include <iostream>
#include <vector>
int main(void) {
Stack<int, std::vector> s1;
s1.push(1);
s1.push(2);
}
int main(void) {
Stack<int, std::vector<int>> s1;
int i1 = 1;
int i2 = 2;
s1.push(i1);
s1.push(i2);
while (!s1.empty()) {
std::cout << s1.top() << " ";
s1.pop();
}
std::cout << "\n";
}
Template Argument Deduction is the process of determining the types (of type parameters) and the values of nontype parameters from the types of function arguments.
template <typename T, int size>
T findmin(const T (&a)[size]) {
T min = a[0];
for (int i = 1; i < size; i++) {
if (a[i] < min) min = a[i];
}
return min;
}
type paremeter
non-type parameter
call parameters
// array to pointer
template <typename T>
f(T* array) {}
int a[] = { 1, 2 };
f(a);
// const qualification
template <typename T>
f(const T item {}
int a = 5;
f(5); // int => const int;
// conversion to base class
// from derived class
template <typename T>
void f(Base<T> &a) {}
template <typename T>
class Derived : public Base<T> { }
Derived<int> d;
f(d);
template <typename T>
T min(T a, T b) {
return a < b ? a : b;
}
int main() {
int i; double d;
min(i, static_cast<int>(d)); // int min(int, int)
min<int>(i, d); // int min(int, int)
min(static_cast<double>(i), d); // double min(double, double)
min<double>(i, d); // double min(double, double)
}