C++ code snippets

C++ code snippets

Some C++ tricks and syntactic sugars

Recording some coding snippets I have learned.

Multiple instancing with Macro

#define INSTANCING_LIST(...) , ##__VA_ARGS__
#define DECLARE(name, ...) name INSTANCING_LIST(__VA_ARGS__)

The magic is in the INSTANCING_LIST. if __VA_ARGS__ is empty then it return nothing, else it will return with a comma append at front. This can solve the issue when multiple instancing declaration doesn’t allow last item end with a comma Like the class inheritance case

A better solution is using c++20 feature __VA_OPT__

Lambda capture a member variable

auto func = [val = data.float](){
  // use val
};

Struct assignment

DataStruct a = {
  .f = 1.f,
  .s = ""
};

Tuple return

std::tuple<Type1, Type2> func(){};
auto[data1, data2] = func();

Template class separate to .inl

// header
template <typename T, int val = 1>
class MyClass {
  void foo();
};
#inclde "class.inl"

// inl
template <typename T, int val>
MyClass<T, val>::foo(){
  // impl
}

std::forward

// SFINAE
template <typename U, std::enable_if_t<std::is_same<T, std::decay_t<U>>::value, int> = 0>
void set(U&& value){
  T val = std::forward<U>(value);
}

Allow both lvalue and rvalue passing through same API. Along the code path, all functions needs to do std::forward C++ type utiles function

Variadic arguments template args

template <typename... Args>
void func(Args&&... args) {
  callback(std::forward<Args>(args)...);
}

Redirect class type

class A {
  operator B() const {
    return this->b;
  };
};
A a;
// Then a can used as B

Compile time type if condition

// require c++17
if constexpr (std::is_same<T, std::string>::value) {
} else {
}

template qualifier

template <typename T>
class Foo {
protected:
  template <typename U>
  void test(){};
};
template <typename D>
class Bar : public Foo<D> {
public:
  void test(){
    Foo<D>::template test<D>();
  }
};
// need to use qualifer template after a ., ->, or :: operator to distinguish member template

Custom compile time type check

template <typename T> static char func(decltype(&T::Reflectable));
template <typename T> static int func(...);
template <typename T>
struct is_reflectable {
  enum { value = (sizeof(func<T>(nullptr)) == sizeof(char)) };
};

class Foo {
public:
  static const bool Reflectable = true;
};

if constexpr (is_reflectable<T>::value) {
}

Stack template

template <typename T>
class Foo{
template <typename U, std::enable_if_t<std::is_same<T, U>::value, int> = 0>
void copy(U&& data);
T data_;
};

// up to 2 stacked templates
template <typename T>
template <typename U, std::enable_if_t<std::is_same<T, U>::value, int>>
void Foo<T>::copy(U&& data) {
  data_ = std::forward<U>(data);
}

Access other class’ private member type

// Only working with Apple Clang...
// Explicit instantiation definitions ignore member access specifiers: parameter types and return types may be private
class Bar{
private:
  std::string data_;
};
class Foo{
public:
  template<typename T, typename M = decltype(T::data_)>
  void print(T t, M data) {
    std::cout << data << std::endl;
  }
};
int main() {
  Foo foo;
  Bar bar;
  foo.print(bar, "123");
}

Obtain the method returned type

#define VALUE_TYPE typename std::result_of<decltype(&ClassName::get)(Classname)>::type

Static factory register and Runtime factory register

// static
class A{
  static void Register() {
    Factory::Register(A::Creator);
  };
  static A* Create();
};

// runtime / user defined
class A_Register {
A_Register(CreatorList& c) {
  c.push_back(...);
}
};
class Factory {
  std::shared_ptr<A_Register> Aregister_ = std::make_shared<A_Register>(c_);
  friend class A_Register;
private:
  CreatorList c_;
}

Compile time turn on/off API base on a compile time boolean

template <bool FLAG>
class Foo {
  // enable_if_t need to work in the type deduce scenario, so we need to use a buffer bool to avoid direct inference
  template <bool U = FLAG, typename std::enable_if_t<U, int> = 0>
  void api();

  template <typename T, typename std::enable_if_t<!FLAG && std::is_same<T, bool>, int> = 0>
  void api(T);
}

macro with template parameter

#define MACRO(...) __VA_ARGS__ a;
MACRO(std::pair<int, bool>);