-
-
Save idfumg/880d3d6a0a96d6a28119c015f6c0bbac to your computer and use it in GitHub Desktop.
D scope guards emulation for C++17 -- https://godbolt.org/g/Vknqur https://godbolt.org/z/nFv3LS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* Copyright (C) 2017-2018 Andreas Hollandt | |
* | |
* Distributed under the Boost Software License, Version 1.0. | |
* See copy at http://boost.org/LICENSE_1_0.txt. | |
*/ | |
#pragma once | |
#include <exception> | |
#include <utility> // forward, move | |
#if _MSC_VER && _MSC_VER < 1914 | |
#error update VS | |
#endif | |
// e.g. gcc 7+ with -std=c++17 | |
#if !_MSC_VER && __EXCEPTIONS && !__cpp_lib_uncaught_exceptions | |
#error C++17 uncaught_exceptions support required | |
#endif | |
#if _MSC_VER | |
#define SUPPRESS_UNUSED_WARNING __pragma(warning(suppress : 4189)) | |
#define SUPPRESS_CONST_CONDITION __pragma(warning(suppress : 4127)) | |
#define ALWAYS_INLINE __forceinline | |
#else | |
#define SUPPRESS_UNUSED_WARNING [[gnu::unused]] | |
#define SUPPRESS_CONST_CONDITION | |
#define ALWAYS_INLINE [[gnu::always_inline]] | |
#endif | |
#define SCOPEGUARDCONCAT2(x, y) x ## y | |
#define SCOPEGUARDCONCAT(x, y) SCOPEGUARDCONCAT2(x, y) | |
//! main macro | |
#define scope(stype) SUPPRESS_UNUSED_WARNING auto&& SCOPEGUARDCONCAT(scopeguard, __LINE__) = \ | |
ScopeGuardForw<ScopeGuardType::stype>() ^ [&]() | |
//! the possible arguments for scope() | |
enum class ScopeGuardType { exit, failure, success }; | |
template <ScopeGuardType stype> | |
struct UncaughtExceptionsTracker | |
{ | |
#if __EXCEPTIONS || _CPPUNWIND | |
int baseline = std::uncaught_exceptions(); | |
bool exraised() const | |
{ | |
return std::uncaught_exceptions() > baseline; | |
} | |
#else | |
static bool exraised() { return false; } | |
#endif | |
}; | |
// empty base class optimization | |
template<> | |
struct UncaughtExceptionsTracker<ScopeGuardType::exit> | |
{ | |
static bool exraised() { return false; } | |
}; | |
//! main RAII guard class | |
template<ScopeGuardType stype, typename F> | |
struct ScopeGuard final : UncaughtExceptionsTracker<stype> | |
{ | |
F f; | |
ALWAYS_INLINE | |
ScopeGuard(F&& f) : f(std::move(f)) {} | |
ALWAYS_INLINE | |
~ScopeGuard() noexcept | |
{ | |
SUPPRESS_CONST_CONDITION | |
if (stype == ScopeGuardType::exit || | |
(this->exraised() == (stype == ScopeGuardType::failure))) | |
f(); | |
} | |
ScopeGuard(const ScopeGuard&) = delete; | |
ScopeGuard(ScopeGuard&&) = delete; | |
void operator=(const ScopeGuard&) = delete; | |
void operator=(ScopeGuard&&) = delete; | |
}; | |
// enables the lambda to be naturally specified after the scope() part | |
template <ScopeGuardType stype> | |
struct ScopeGuardForw | |
{ | |
template <typename F> | |
ALWAYS_INLINE | |
ScopeGuard<stype, F> | |
operator^(F&& f) const | |
{ | |
return { std::forward<F>(f) }; | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "scopeguard.h" | |
#include <cstdio> | |
auto foo() | |
{ | |
auto f = new int(5); | |
scope(exit) | |
{ | |
delete f; | |
}; | |
scope(failure) | |
{ | |
puts("it failed"); | |
}; | |
return *f; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment