int max(int a, int b) { return a > b ? a : b; }
double max(double a, double b) { return a > b ? a : b; }
complex max(complex a, complex b)
{
return a > b ? a : b;
}
template<typename T>
T max(T a, T b)
{
return a > b ? a : b;
}
template<typename T>
T max(const T &a, const T &b)
{
return a > b ? a : b;
}
template<typename Something>
void swap(Something &x, Something &y)
{
Something t = x;
x = y;
y = t;
}
class IntStack
{
protected:
int height;
int items[50];
public:
IntStack() : height(0) { }
void push(int x) { items[height] = x; ++height; }
int pop() { height--; return items[height]; }
int top() const { return items[height - 1]; }
int size() const { return height; }
bool isEmpty() const { return height <= 0; }
bool isFull() const { return height >= 50; }
};
template<typename ItemType>
class Stack
{
protected:
int height;
ItemType items[50];
public:
Stack() : height(0) { }
void push(const ItemType &x) { items[height] = x; ++height; }
ItemType pop() { height--; return items[height]; }
ItemType top() const { return items[height - 1]; }
int size() const { return height; }
bool isEmpty() const { return height <= 0; }
bool isFull() const { return height >= 50; }
};
Stack<int> nums; nums.push(42); cout << nums.pop();
// reverse letters
Stack<char> lets;
char c;
cin >> c;
while ( cin.good() )
{
lets.push(c);
cin >> c;
}
while ( !lets.isEmpty() )
cout << lets.pop();
Stack<Stack<int>> ss;
lets.push(1e30); // illegal!
lets.push("some string"); // illegal!
This is why
lets.pop()
doesn't need a type cast.
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<>();
nums.add(20);
test(nums);
System.out.println(nums.get(0));
System.out.println(nums.get(1));
}
public static void test(ArrayList myList) { // note: no item type
myList.add("duck");
}
}
which prints
20
duck
C:\> java java-template-bug.java Note: java-template-bug.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. 20 duck
class BaseContainer { ... };
template<typename X> class Container : public BaseContainer{...};
template<typename ItemType, int size>
class Stack
{
protected:
int height;
ItemType items[size];
public:
Stack() : height(0) { }
void push(ItemType x) { items[height] = x; ++height; }
ItemType pop() { height--; return items[height]; }
bool isEmpty() const { return height <= 0; }
bool isFull() const { return height >= size; }
};
Stack<int, 1000> bigstack;
void dump(Stack<int, 1000> nums) { ...pop and print all... }
dump(bigstack);
Stack<int, 1001> xs;
dump(xs); -- illegal!
template<int size>
void dump(Stack<int, size> nums) { ... }
dump(bigstack);
Stack<int, 1001> xs;
dump(xs); // ok
typedef int num;
...
num x, y;
x = 100; y = x * x;
int z = y; // can mix int and num
typedef Stack<int, 1000> LgIntStack;
...
LgIntStack nums;
template<class ItemType, int size>
class Stack
{
protected:
int height;
ItemType items[size];
#include <vector>
using namespace std;
...
vector<string> roster;
string name;
cin >> name;
while ( cin.good() ) {
roster.push_back(name);
cin >> name;
}
cout << "Read " << roster.size() << names << endl;
cout << "First name: " << roster[0] << endl;
class Student { ... };
vector<Student*> csc2210_roster;
csc2210_roster.push_back(new Student("Tricia", 1823435));
csc2210_roster[0]->print();
list_iterator.cpp
for adding elements, processing all elements
.begin, .end: explicit iteration over
the container
repeated_words.cpp
#include <map>
....
map<string, int> ids;
ids["Shareem"] = 934;
if ( ids.find("Kira") == ids.end() )
cout << "Kira not found." << endl;
class SIterator
{
SNode *current;
public:
SIterator(SNode *s) : current(s) { }
const string& next() const { return current->item; }
bool hasNext() const { return current != nullptr; }
void operator++() // PREINCREMENT operator
{
assert(hasNext());
current = current->next;
}
};
class SList
{
public:
...
SIterator iterator() const { return SIterator(head); }
...
};
SList names;
... add items to names
for(SIterator it = names.iterator(); it.hasNext(); ++it)
{
SIterator dup_it = it;
if ( dup_it.hasNext() )
++dup_it; // skip past current item in list
while ( dup_it.hasNext() && it.next() != dup_it.next() )
++dup_it;
if ( dup_it.hasNext() ) // stopped because found item
cout << "Duplicate entry in list: " << dup_it.next() << endl;
}
pair<double, double> ave_and_stdev(vector<double> xs) {
if ( xs.size() == 0 )
return <0, 0>;
double sum = 0.0, sum_sq = 0.0;
for(x in xs) {
sum += x;
sum_sq += x * x;
}
pair<double, double> result;
result.first = sum / double(xs.size());
result.second = sum_sq / (double(xs.size() - 1));
return result;
}
vector<float> sizes;
... code to read sizes ...
sort(sizes.begin(), sizes.end()); // O(N log N)
reverse(sizes.begin(), sizes.end());
float nums[50];
... code to read numbers ...
sort(&nums[0], &nums[50]);
Note how the address of the element just past the last array
element was used to mark the array end.
def f(a, b, c):
return (a + b) * c
x = f(1, 2, 3)
y = f(3.5, 4.7, 8.9)
type(x) would give int, type(y)
would give float
a, b
f('ax', 'by', 3)
returns axbyaxbyaxby - why?
'ax' + 'by' gives 'axby'
string * n gives n copies of the string:
so 'axby'*3 gives 'axbyaxbyaxby'
axby * 3 and
just calls the multiplication method for a string
f('a', 'b', 'c') fails because 'ab' *
'c' undefined - there is no way to multiply two strings
something.g
where something is an object of type X, then
the call succeeds if X or a superclass has method g
class Duck
and class Whale]
toString method, draw any
object with a draw method, etc.
std::list
sort method, so the code
list<int> nums;
int x;
cin >> x;
while ( cin ) {
nums.push_back(x);
cin >> x;
}
nums.sort()
for(int x : nums) cout << x << endl;
works fine.
location objects
(capturing lattitude and longitude for each point on Earth)
and there's no way to compare locations
list<location> places is legal as long as we
there is no call places.sort()
list<stack<string>> is
legal, even though there is no < operation on stacks
#include <iostream>
#include <list>
using namespace std;
class location {
public:
location(float lat, float lon) : _lattitude{lat}, _longitude{lon} { }
float lattitude() const { return _lattitude; }
float longitude() const { return _longitude; }
private:
float _lattitude, _longitude;
};
int main() {
list<location> places_to_visit;
places_to_visit.sort();
return 0;
}
-*- mode: compilation; default-directory: "c:/web/csc2210/notes/support/" -*-
Compilation started at Tue Nov 7 12:08:32
g++ --std=c++20 odd_template_error.cpp
In file included from C:/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/lib/gcc/x86_64-w64-mingw32/12.2.0/include/c++/list:63,
from odd_template_error.cpp:4:
C:/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/lib/gcc/x86_64-w64-mingw32/12.2.0/include/c++/bits/stl_list.h: In instantiation of 'bool std::__detail::_Scratch_list::_Ptr_cmp<_Iter, void>::operator()(std::__detail::_List_node_base*, std::__detail::_List_node_base*) const [with _Iter = std::_List_iterator<location>]':
C:/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/lib/gcc/x86_64-w64-mingw32/12.2.0/include/c++/bits/stl_list.h:203:18: required from 'void std::__detail::_Scratch_list::merge(std::__detail::_List_node_base&, _Cmp) [with _Cmp = _Ptr_cmp<std::_List_iterator<location>, void>]'
C:/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/lib/gcc/x86_64-w64-mingw32/12.2.0/include/c++/bits/list.tcc:515:23: required from 'void std::__cxx11::list<_Tp, _Alloc>::sort() [with _Tp = location; _Alloc = std::allocator<location>]'
odd_template_error.cpp:18:23: required from here
C:/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/lib/gcc/x86_64-w64-mingw32/12.2.0/include/c++/bits/stl_list.h:188:34: error: no match for 'operator<' (operand types are 'location' and 'location')
188 | { return *_Iter(__lhs) < *_Iter(__rhs); }
| ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
[followed by another 100+ lines of error output]
IntStack s;
...
s.push(100);
IntStack s; // see above
s.push(42);
int x = s.pop();
is compiled as
...
s.items[s.height] = 42; ++s.height;
int x = (s.height--, s.items[s.height]); // no calls
making further optimizations possible:
...
s.items[s.height] = 42; ++s.height;
int x = (s.height--, s.items[s.height]);
or even
int x = 42;
const int MILLION = 1000000;
Vector nums(MILLION);
for(int i = 0; i < MILLION; ++i)
nums[i] = 1 / double(i);
for(int i = 0; i < MILLION; ++i) {
int &tmp = (if ( i < 0 || i >= nums._size )
throw std::out_of_range("Illegal index into vector."),
&nums.elements[i]);
tmp = 1 / double(i);
}
const int MILLION = 1000000;
Vector nums(1000000); // nums._size = 1000000
for(int i = 0; i < 1000000; ++i) {
int &tmp = (if ( i < 0 || i >= 1000000 )
throw std::out_of_range("Illegal index into vector."),
nums.elements[i]);
tmp = 1 / double(i);
}
const int MILLION = 1000000;
Vector nums(1000000);
for(int i = 0; i < 1000000; ++i)
nums.elements[i] = 1 / double(i);
template<typename T> inline
T max(T a, T b)
{
return a > b ? a : b;
}
push_back has no runtime overhead
- just manipulate the container directly
.find would translate to a simple loop
using the iterator
.insert for a
BST, .sort, will turn into library function calls, but
still have minimal overhead
inline and templates