Last active
October 24, 2017 12:03
-
-
Save blapid/a8e32107845a19c6e8611a7b83818a72 to your computer and use it in GitHub Desktop.
Experiments with C++17 constructor template argument deduction and unit testing static asserts. Tested on Ubuntu 16.04.3, Clang 5.0.1-svn314893
This file contains 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 "llcpp/llcpp.hpp" | |
#include <stdio.h> | |
#include <utility> | |
// typestring.hpp | |
template<typename CharT, CharT... Chars> | |
struct typestring { | |
static constexpr const CharT *data() { return chars; } | |
static constexpr std::size_t len = sizeof...(Chars); | |
static constexpr CharT chars[len + 1] = {Chars..., '\0'}; | |
}; | |
template<typename CharT, CharT... Chars> | |
constexpr auto operator"" _ts() noexcept | |
{ | |
return typestring<CharT, Chars...>{}; | |
} | |
// static_assert.hpp | |
struct disable {}; | |
struct enable { | |
constexpr operator disable() const { return disable{}; } | |
}; | |
template<class T> struct StaticAssert { | |
using _T = T; | |
using is_disabled = std::is_same<T, disable>; | |
constexpr StaticAssert(T&& t) {} | |
template<bool Condition> | |
constexpr bool Check() { | |
static_assert(is_disabled::value || Condition, ""); | |
return Condition; | |
} | |
template<bool Condition, typename Typestring> | |
struct bool_with_message { | |
using Result = std::conditional_t<Condition, std::true_type, std::false_type>; | |
using Message = Typestring; | |
constexpr operator bool() const { return Condition; } | |
constexpr const char *message() const { return Typestring::data(); } | |
}; | |
template<bool Condition, typename Typestring> | |
constexpr auto Check() -> bool_with_message<Condition, Typestring> { | |
static_assert(is_disabled::value || Condition, ""); | |
return bool_with_message<Condition, Typestring>{}; | |
} | |
}; | |
// additional deduction guide | |
#define DISABLE_OPT(OPT) StaticAssert(OPT&& t) -> StaticAssert<disable>; | |
// Disable all | |
#define DISABLE_ALL template<typename T> StaticAssert(T&& t) -> StaticAssert<disable>; | |
// Disable some static asserts | |
struct enable_opt1 : public enable { | |
}; | |
//DISABLE_OPT(enable_opt1) | |
struct enable_opt2 : public enable { | |
}; | |
#define STATIC_ASSERT_OPT_OR_RESULT(COND, MESSAGE, OPT) StaticAssert(OPT{}).Check<COND, decltype(MESSAGE##_ts)>() | |
#define STATIC_ASSERT_OR_RESULT(COND, MESSAGE) STATIC_ASSERT_OPT_OR_RESULT(COND, MESSAGE, enable) | |
#define NAMED_STATIC_ASSERT_OPT(NAME, COND, MESSAGE, OPT) static constexpr auto NAME = STATIC_ASSERT_OPT_OR_RESULT(COND, MESSAGE, OPT) | |
#define NAMED_STATIC_ASSERT(NAME, COND, MESSAGE) NAMED_STATIC_ASSERT_OPT(NAME, COND, MESSAGE, enable) | |
// test.cpp | |
DISABLE_ALL | |
struct a { | |
//static constexpr auto test1 = STATIC_ASSERT_OR_RESULT(0==1, "Test message"); | |
NAMED_STATIC_ASSERT(test1, 0==1, "Test message"); // Requires DISABLE_ALL | |
using test2 = decltype(STATIC_ASSERT_OR_RESULT(0==1, "Test2")); // Requires DISABLE_ALL | |
}; | |
int main(int argc, char* argv[]) | |
{ | |
static_assert(std::is_empty_v<StaticAssert<enable>>, "Should be empty"); | |
static_assert(std::is_empty_v<StaticAssert<disable>>, "Should be empty"); | |
static_assert(std::is_empty_v<decltype("Test"_ts)>, "Should be empty"); | |
static_assert(std::is_empty_v<decltype(STATIC_ASSERT_OR_RESULT(0==0, "Test"))>, "Should be empty"); | |
bool tmp; | |
tmp = StaticAssert(disable{}).Check<0==0>(); | |
printf("tmp: %s, expect True\n", (tmp) ? ("True") : ("False")); | |
tmp = StaticAssert(disable{}).Check<0==1>(); | |
printf("tmp: %s, expect False\n", (tmp) ? ("True") : ("False")); | |
tmp = StaticAssert(enable{}).Check<0==0>(); | |
printf("tmp: %s, expect True\n", (tmp) ? ("True") : ("False")); | |
tmp = StaticAssert(enable{}).Check<0==1>(); // Requires DISABLE_ALL | |
printf("tmp: %s, expect False\n", (tmp) ? ("True") : ("False")); | |
tmp = StaticAssert(enable_opt1{}).Check<0==1>(); // Requires DISABLE_OPT(enable_opt1) or DISABLE_ALL | |
printf("tmp: %s, expect False\n", (tmp) ? ("True") : ("False")); | |
tmp = StaticAssert(enable_opt2{}).Check<0==1>(); // Requires DISABLE_OPT(enable_opt2) or DISABLE_ALL | |
printf("tmp: %s, expect False\n", (tmp) ? ("True") : ("False")); | |
tmp = STATIC_ASSERT_OR_RESULT(0==1, "Big assert message"); // Requires DISABLE_ALL | |
printf("tmp: %s, expect False\n", (tmp) ? ("True") : ("False")); | |
printf("struct a: %s, expect False. Message %s\n", (a::test1) ? ("True") : ("False"), a::test1.message()); | |
printf("struct a: %s, expect False. Message %s\n", (a::test2::Result::value) ? ("True") : ("False"), a::test2::Message::data()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment