- Header only
- Low dependence:
no dependency on other headers(include which from inc/) except which from ISO C++.
Functionality | Documentation | Header | Test |
---|---|---|---|
Unit testing | UnitTest.hh | UnitTest.hh | see test |
Wrap async call to avoid callback hell | AsyncWrapper.hh | AsyncWrapper.hh | here |
Danamic generic type | Any.hh | Any.hh | here |
Uninitialized concept | Optional.hh | Optional.hh | here |
multi-type, single value container | Variant.hh | Variant.hh | here |
compile-time function information | function_traits.hh | here | |
scope guard | ScopeGuard.hh | ScopeGuard.hh | here |
To use the header, just copy which you need to your include dictionary.
Extremely small unit testing framework.
#define TEST_MAIN /**< this will insert main function to this compile unit atomaticly */
#include "UnitTest.hh"
TEST_CASE(a_test_case)
{
TEST_REQUIRE(condition); /**< if this fail, the next lines in this case will not be executed */
TEST_CHECK(condition); /**< if this fail, failure will be report, but test go on */
TEST_CHECK(condition, "extra dialog msg"); /**< if this fail, "extra dialog msg" will be printed. */
TEST_REQUIRE(condition, "multi", "line", "extra", "msg");
TEST_CHECK(condigion, []{ /** do something here */ });
TEST_REQUIRE(condition, logger, args_to_logger); /**< logger can be any callable object */
throw some_thing{msg}; /**< this exception will be caught by unit testing framework and a failure will be report */
}
TEST_CASE(another_test_case)
{
*(int *)0 = 0; /**< the unit test framewrok will caught SIGSEGV and terminate all tests */
}
Designed to avoid deep callback.
Compare codes bellow, you can't miss it.
With lambda, we always do callbacks like this:
async_function(params, [](callback_param_decls)
{
if(need_do_another_async_operation())
{
another_async_function(params, [](callback_param_decls)
{
if(need_do_yet_another_async_operation())
{
yet_another_async_function(params, [](callback_param_decls)
{
/** what if we need more async operations? */
}
}
});
}
});
Now, we can do it in this way:
wrapAsync([](auto callback, callback_param_decls)
{
async_func(params, callback);
}).then([](auto callback, callback_param_decls)
{
if(need_do_another_async_operation())
another_async_function(params, callback);
}).then([](auto callback, callback_param_decls)
{
if(need_do_yet_another_async_operation())
yet_another_async_function(params, callback);
}) /**< if need more async operation, just write .then(...), and at then end of the then list, we should: */
.apply();
The Any class is a variant value type based on the second category.
It supports copying of any value type and safe checked extraction of that value strictly against its type.
Any a, b = 47; /**< a contains null, b contains int(47) */
if(b.is<int>()) /**< check if b contains a int, should be true */
{
a = b.get<int>(); /**< take which b contains, now a and b both contain int(47) */
Any c = a; /**< c contains int instead of Any */
std::cout << c.get<bool>() << std::endl; /**< this will throw std::bad_cast */
}
Class template Optional is a wrapper for representing 'optional' (or 'nullable') objects who may not (yet) contain a valid value.
Optional<int> opt; /**< maybe contains bool */
if(opt) /**< check if opt is initialized, will be false */
{
/** do something */
}
else
{
opt = 47; /**< now, opt is initialized */
Optional<int> opt1 = opt; /**< now, opt and opt1 contains the same thing */
Optional<std::string> opt2 = opt; /**< compile error */
Optional<std::string> opt3 = 3; /**< compile error */
}
The variant class template is a safe, generic, stack-based discriminated union container,
Whereas standard containers such as std::vector may be thought of as "multi-value, single
type," variant is "multi-type, single value."
Variant<int, bool, std::string> var; /**< may contains int, bool or std::string */
var = 47; /**< now contains int, var.is<int>() will be true */
if(var.is<int>()) /**< check if var contains int */
std::cout << var.get<int>() << std::endl; /**< get int from variant */
Variant<int, bool, std::string> var1 = var; /**< var1 contains the same thing as var */
Variant<int, bool, std::string> var2 = "string"; /**< compile error */
Variant<int, bool, const char*> var3 = "const char*"; /**< ok */
Variant<int, bool, std::string> var4 = std::string{"string"}; /**< ok */
HANDLE func()
{
HANDLE h = CreateSomeObject(...);
ScopeGuard onErrorExit([&] { CloseHandle(h); h = nullptr; });
//...
if(error0_occur)
{
return nullptr;
}
//...
if(error1_occur)
{
return nullptr;
}
//...
onErrorExit.dismiss() // no error occur
return h;
}