Skip to content

Instantly share code, notes, and snippets.

@TheTomster
Created September 30, 2012 04:27
Show Gist options
  • Save TheTomster/3805835 to your computer and use it in GitHub Desktop.
Save TheTomster/3805835 to your computer and use it in GitHub Desktop.
#include <iostream>
// This file is kind of crazy because of the names, but here goes...
// Foo is our template class. It holds a thing of type T, called the_t.
// When someone creates a new Foo, it creates a T with T::T() and saves it.
// Then, someone can call Foo.foobar and pass us an "uber" of type U.
// The uber needs to have a spork function, which accepts a T.
// the type signature looks like this:
// void U::spork(T);
template <class T>
class Foo {
private:
T the_t;
public:
template <class U>
void foobar(U& uber) {
uber.spork(the_t);
}
};
// structs are just like classes in c++, but things are public by default.
struct Bar {
int count;
// initialization list here... they probably glazed over it. basically it's
// crazy syntax that sets count to 0. Ask me sometime if you're curious about
// these :-)
Bar() : count(0) {}
};
struct Potato {
int increment;
Potato(int i)
: increment(i) { }
// notice that i'm using a reference here! this is very important because the
// default behavior is to create a copy of b, modify it, and then throw it
// away. we want to actually change whatever the caller gives us. You could
// also use pointers for this but pointers suck.
void spork(Bar& b) {
b.count += increment;
std::cout << b.count << std::endl;
}
}; // don't forget these asshole semicolons on class / struct
struct Koala {
int increment;
Koala(int i)
: increment(i) { }
void spork(Bar& b) {
b.count -= increment;
std::cout << b.count << std::endl;
}
};
int main() {
// so here we create a Foo<Bar> called f. So anywhere up in Foo where it
// says T, is going to be a Bar. f.the_t has a counter set to 0.
Foo<Bar> f;
// Now we set up a Potato, and set Potato's increment to 12.
Potato p(12);
// Now the magic happens. We call f.foobar(p).
// Let's look at the types here.
// f is a Foo<Bar>
// p is a Potato
// So if we fill in those types and variable names in f.foobar... the source
// looks like this:
// foobar(Potato uber) { // uber is a copy of the p we passed in
// uber{Potato}.spork(the_t{Bar}); // I put the type in {}
// }
// At compile time, the compiler checks to make sure these types make sense.
// It asks: Does Potato have a function "void spork(Bar)"? It does! So it
// generates code for that and the compilation proceeds.
f.foobar(p);
f.foobar(p);
f.foobar(p);
// The generic-ness comes in when we make a new thing that fits the "U" type
// in Foo's templates. Here I make a Koala that subtracts from Bar's counter
// instead of adding.
Koala k(3);
f.foobar(k);
f.foobar(k);
f.foobar(k);
// I hope that all makes sense! It's a shitty example because I'm just
// derping around to see if this works, but it does!
//
// Here's the output. You see the result is that f.the_t's counter gets
// incremented 12 at a time, and then decremented 3 at a time! IT'S WORKING!
//
// Tom@Squidward ~/sandbox
// $ ./crazy_names.exe
// 12
// 24
// 36
// 33
// 30
// 27
//
// In summary: lol c++
return 0;
}
template<class T>
class Foo {
private:
T the_t;
public:
T get_the_t();
};
#include <iostream>
class Waffle {
public:
void fooderate() {
using namespace std;
cout << "I am a waffle!" << endl;
}
};
template<class Breakfast>
void fooderator(Breakfast& f) {
f.fooderate();
}
int main() {
Waffle w;
fooderator(w);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment