random c++ stuff that might be leeched off the internet

std::shared_ptr<void>

since shared_ptr stores a type-erased deleter, you can do the following

void foo() {
  std::shared_ptr<void> p(new A);
  p.reset(new B); // ~A() called here
} // ~B() called here

writing an allocator

signature of an allocator that will work with std::vector<int, myalloc<int>>

template <typename T>
struct myalloc {
    using value_type = T;
    T* allocate(size_t n) {...}
    void deallocate(T*, size_t n) {...}
    // probably delete copy ctor and copy assign too
};

generating switch statements with templates

from my stack overflow question

template <int ...Key>
void foo(int key) {
  switch (key) {
      case 1: bar<1>();break;
      case 3: bar<3>();break;
      case 5: bar<5>();break;
      case 7: bar<7>();break;
      case 9: bar<9>();break;
      default: break;
  }
}

can be re-written as

template <int ...Keys>
void foo(int key) {
    ([&]() {
        if (key == Keys) {
            bar<Keys>();
            return true;
        }
        return false;
    }() || ...);
}

counting the number of member fields of a trivial struct

struct X {
    int a;
    int b;
};

struct OmegaType {
    template <typename T>
    operator T() {}
};

template <typename T>
constexpr size_t count_member(auto... args) {
    if constexpr (requires {T{args...};} == false) {
        return sizeof...(args) - 1;
    } else {
        return count_member<T>(args..., OmegaType{});
    }
}

static_assert(count_member<X>() == 2);

OmegaException

From cppcon

#include <string>
#include <source_location>
#include <iostream>

template <typename DATA_T>
class OmegaException {
  public:
    OmegaException(
        std::string str,
        DATA_T data,
        const std::source_location& loc = std::source_location::current()
        // std::stacktrace trace = std::stacktrace::current()
        ) :
        err_str_{std::move(str)},
        user_data_{std::move(data)},
        location_(loc)
        // backtrace_(trace)
        {}

    std::string& what() {return err_str_;}
    const std::string& what() const noexcept { return err_str_; }
    const std::source_location& where() const noexcept { return location_; }
    // const std::stacktrace& stack() const noexcept { return backtrace_; }
    DATA_T& data() { return user_data_; }
    const DATA_T& data() const noexcept { return user_data_; }

  private:
    std::string err_str_;
    DATA_T user_data_;
    const std::source_location location_;
    // const std::stacktrace backtrace_;
};

int main() {
    try {
        throw OmegaException<int>("oh no", 5);
    } catch (const OmegaException<int>& e) {
        std::cout << e.where().file_name() << std::endl;
    }
}

destructors should almost never throw exceptions

If an exception is thrown during an exception handling, std::terminate is triggered. Objects are popped off the stack and destructed during stack rewinding, and if one of these puppies throw, your program dies! See isocpp faq.

defining a static class member

A declaration of a struct variable within the struct definition don’t define the struct. An external definition is required.

struct S {
    static int X = 5; // declares, not defines
};
int S::X; // defines

int main() {
    int y = S::X; // S::X is not not odr-use
    v.push_back(S::X); // push_back takes a reference - S::X is odr-use, requires a definition
}

Probably prefer (... <op> Ts) to (Ts <op> ...>)

if op isn’t a commutative operator, (Ts <op> ...) probably don’t do what you expect.

template<int... Ts>
int foo() {
    return (Ts - ...);
}

template<int... Ts>
int bar() {
    return (... - Ts);
}

// foo<10,2,3>() -> 11
// bar<10,2,3>() -> 5

type hack

Sadly the commitee hated this and swore to break this some day.

#include <string>
#include <type_traits>

template<int N> struct tag{};

template<typename T, int N>
struct loophole_t {
  friend auto loophole(tag<N>) { return T{}; };
};

auto loophole(tag<0>);
auto loophole(tag<1>);

int main() {
    sizeof( loophole_t<std::string, 0> );
    sizeof( loophole_t<int, 1> );

    static_assert(std::is_same_v<std::string, decltype( loophole(tag<0>{}) ) >);
    static_assert(std::is_same_v<int, decltype( loophole(tag<1>{}) ) >);
}

Separator argument

Have a function that takes in a char as separator? Make it a template arument to save one register!

template <char c>
void foo(const std::vector<std::string>& v) {
    // <some concat logic maybe?>
}

delete move constructor

This is an extension of the rule of 5. Specifically, X WILL NOT generate a move constructor but Y will.

struct X {
    virtual ~X() = default;
    // no move ctor generated due to user defined dtor.
};

struct Y : X {
    // move ctor is generated since there is no user defined dtor.
};

strange syntax

void foo(int fn(double)) // fn is a pointer-to-function

getting the offset of a base class from a derived class

struct A {
    int a1, a2, a3;
};

struct B {
    int b;
};

struct C : A, B {
    int c, c1;
};

template <typename Parent, typename Child>
consteval size_t getoffset() {
    union {Child c; char b[sizeof(Child)];} u;
    auto* a1 = (static_cast<void*>(std::addressof(static_cast<Parent&>(u.c))));

    for (int i = 0; i < sizeof(Child); ++i) {
        auto* a2 = (static_cast<void*>(std::addressof(u.b[i])));
        if (a1 == a2) {
            return i;
        }
    }
}
static_assert(getoffset<A, C>() == 0);
static_assert(getoffset<B, C>() == 12);

Calendar tricks

days in month

// compute day of a month
days_in_month = [](int month) { return ((month > 3) ^ month) & 30; };
// compute day of a month
is_leap_year = [](int year) -> bool { return (year % 25) == 0 ? (year % 16) == 0 : (year % 4) == 0; };
// perform year % 25 first since its easily predictable
//     if so: check if its divisible by 16
//     else: simply check if its divisible by 4
// these should compile to
// year % 25 // converted to an imul, add and cmp, which is relatively cheap (5 cycles)
// ? : // converted to cmov