Skip to content

Instantly share code, notes, and snippets.

@crcrpar
Created August 16, 2020 02:19
Show Gist options
  • Save crcrpar/0c49633356cf4fc9aaa2d54d74a1294c to your computer and use it in GitHub Desktop.
Save crcrpar/0c49633356cf4fc9aaa2d54d74a1294c to your computer and use it in GitHub Desktop.
template things
// ref: https://www.youtube.com/watch?v=VIz6xBvwYd8
#include <stdio.h>
#include <type_traits>
#include <memory>
template <typename Element>
struct tree_iterator {
tree_iterator& operator ++();
static std::false_type support_plus;
// In practice
// using support_plus = std::false_type;
};
template <class Element>
struct vector_iterator {
vector_iterator& operator ++();
vector_iterator operator + (int);
static std::true_type support_plus;
// In practice
// using support_plus = std::true_type;
};
template <class Element>
struct vector {
using iterator = vector_iterator<Element>;
};
template <class Element>
struct set {
using iterator = tree_iterator<Element>;
};
template <class Iter>
Iter advance(Iter begin, int n) {
for (int i = 0; i < n; ++i) {
++begin;
}
return begin;
}
template <class E>
vector_iterator<E> advance(vector_iterator<E> begin, int n) {
return begin + n;
}
template <class It>
It advance_impl(It begin, int n, std::false_type /* sp */) {
for (int i = 0; i < n; ++i) {
++begin;
}
return begin;
}
template <class It>
It advance_impl(It begin, int n, std::true_type /* sp */) {
return begin + n;
}
template <class Iter>
auto advance(Iter begin, int n) {
return advance_impl(begin, n, Iter::supports_plus);
// In practice
// return advcnce_impl(begin, n, typename Iter::support_plus{});
// Create an object of that type
}
// `template` things
struct S1 { static constexpr int A = 0; };
template <class T>
void fooS1(int x) {
T::A<0>(x);
}
struct S2 { template<int N> static void A(int) {} };
template <class T>
void fooS2(int x) {
T::template A<0>(x);
}
struct S3 { template<int N> struct A{}; };
template <class T>
void fooS3(int x) {
typename T::template A <0> (X);
}
template <class /*Iter*/>
struct iter_traits {
using support_plus = std::false_type;
};
template <class T>
struct iter_traits<T *> {
using support_plus = std::true_type;
};
template <class T>
struct iter_traits<vector_iterator<T>> {
using support_plus = std::true_type;
};
// Now the advance function becomes...
#if 0
template <class Iter>
auto advance (Iter begin, int n) {
return advance_impl(
begin, n,
typename iter_traits<Iter>::supports_plus{}
);
}
#endif
// STL best practice: _t synonyms
template <class Iter>
using iter_supports_plus_t =
typename iter_traits<Iter>::supports_plus;
template <class Iter>
auto advance2(Iter begin, int n) {
return advance_impl(
begin, n,
iter_supports_plus_t<Iter>{}
);
}
template <class T>
int a() { return 1; }
template int a<int>();
template <class T>
void g() {
static_assert(sizeof(T) == 4);
}
void stub_g() {
g<int>();
}
template <class T> int ff1();
template <class T> int ff2() { static_assert(sizeof(T) == 2); }
template <class T> int ff3() { static_assert(sizeof(T) == 2); }
// extern template int ff3<int>();
template <> int ff3<int>() { return 1; }
int ff1_a = ff1<int>();
// int ff2_a = ff2<int>();
int ff3_a = ff3<int>(); // as ff3<int> has an explicit instantiation
template <typename T> int vt;
int vt_i = vt<int>;
// variadic templates
using Cat = unsigned long long;
template <class T, class... Args>
void mcdonald(void *where, Args&&... args) {
new (where) T(std::forward<Args>(args)...);
}
void populate(void *here, void *there, int meow) {
mcdonald<Cat>(here, meow);
// Why the below doesn't compile?
// mcdonald<Cat>(there, meow, meow);
}
// Type deduction in a nutshell, v2
template <class T, class... Us>
void variadic_f(Us... us) { puts(__PRETTY_FUNCTION__); } // MSVC: __FUNCSIG__
void stub_variadic_f() {
variadic_f<char>(0, 1, 2); // [T=char, Us=<int, int, int>]
variadic_f<char, char>(0, 1, 2); // [T=char, Us=<char, int, int>]
}
template <class T, class... Us, class V> void f_v2();
// auto stub_f_v2 = []() {
// f_v2<int, char, int>(); // T=int, Us=<char, int>, V can't be deduced.
// };
template <class... Ts, class U> void g_v2(U);
auto stub_g_v2 = []() {
g_v2<int, char>(3.1); // Ts=<int, char>, U=double
};
template <class... Ts> void h_v2(Ts...);
auto stub_h_v2 = []() {
h_v2<int, char>(0, 0, 3.1); // Ts=<int, char, double>
};
template <class... Ts, class U> void f_v2_1(U, Ts...);
auto stub_f_v2_1 = []() {
f_v2_1('x', 1, 2); // U=char, Ts=<int,int>
};
template <class T, class... Us> void g_v2_1(Us... us, T);
// auto stub_g_v2_1 = []() {
// g_v2_1('x', 1, 2); // us doesn't contribute to deduction, fails!
// };
template <class T, class... Us> void h_v2_1(Us... us, T);
auto stub_h_v2_1 = []() {
h_v2_1<int, int, int>('x', 1, 2);
};
/**
* Two patterns to know:
* The CRTO
* The Mixin Pattern
*/
// CRTP
struct Cat1 {
void speak() { puts("mewo"); }
void speaktwice() { speak(); speak(); }
};
struct Dog1 {
void speak() { puts("woof"); }
void speaktwice() { speak(); speak(); }
};
// template <auto>
template <class Ty, Ty Value>
struct integral_constant {
static constexpr auto value = Value;
};
using fortytwo_type = integral_constant<int, 42>;
using true_type = integral_constant<bool, true>;
// C++17
template <auto Value>
struct new_integral_constant {
static constexpr auto value = Value;
};
using fortytwo_type_17 = new_integral_constant<42>;
using true_type_17 = new_integral_constant<true>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment