Skip to content

Instantly share code, notes, and snippets.

@blapid
Last active October 24, 2017 12:03
Show Gist options
  • Save blapid/a8e32107845a19c6e8611a7b83818a72 to your computer and use it in GitHub Desktop.
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
#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