Skip to content

Instantly share code, notes, and snippets.

@elbeno
Last active August 29, 2015 14:21
Show Gist options
  • Save elbeno/33881ff770805d8375d2 to your computer and use it in GitHub Desktop.
Save elbeno/33881ff770805d8375d2 to your computer and use it in GitHub Desktop.
WITH macro for C++
#include <algorithm>
#include <cassert>
#include <utility>
#include <iostream>
using namespace std;
class Light
{
public:
void turn_on() { m_on = true; };
void turn_off() { m_on = false; }
bool is_on() const { return m_on; }
private:
bool m_on = false;
};
class LightGuard
{
public:
explicit LightGuard(Light& l) : m_light{&l} { m_light->turn_on(); }
~LightGuard() { if(m_light) m_light->turn_off(); }
LightGuard(LightGuard&& rhs) : m_light{std::move(rhs.m_light)} { rhs.m_light = nullptr; }
LightGuard& operator=(LightGuard&& rhs)
{
std::swap(m_light, rhs.m_light);
return *this;
}
LightGuard(const LightGuard& rhs) = delete;
LightGuard& operator=(LightGuard& rhs) = delete;
private:
Light* m_light = nullptr;
};
template <typename T>
struct always_true
{
explicit always_true(T what) : x{std::move(what)} {}
always_true(always_true&& other) : x{std::move(other.x)} {}
constexpr operator bool() const { return true; }
T x;
};
template <typename T>
auto make_true(T&& what) -> always_true<T>
{
static_assert(std::is_move_constructible<T>::value,
"make_true argument must be move constructible");
return always_true<T>{std::forward<T>(what)};
}
#define WITH(what) \
if (auto with_always_true = make_true(what))
Light the_light;
void prepare_drinks()
{
if (the_light.is_on())
cout << "Preparing drinks" << endl;
}
void watch_movie()
{
if (!the_light.is_on())
cout << "Watching movie" << endl;
}
int main()
{
WITH(LightGuard{the_light})
{
assert(the_light.is_on());
prepare_drinks();
}
assert(!the_light.is_on());
watch_movie();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment