4

I'm implementing MY_VERIFY macro to verify values at runtime and terminate if value is bad. Currently I use the following version of MY_VERIFY:

template <typename T>
using DecayLvalueRef =
  typename std::conditional_t<
    std::is_lvalue_reference_v<T>,
    T, typename std::decay_t<T>>;

#define MY_VERIFY(expr, ...) \
  [&](auto&& _expr) constexpr noexcept -> DecayLvalueRef<decltype(_expr)> { \
    if (!static_cast<bool>(_expr)) { \
      printf("" __VA_ARGS__); \
      printf("\n"); \
      exit(-1); \
    } \
    return std::forward<decltype(_expr)>(_expr); \
  }(expr)

The point is not only to check expr, but also return it if check is ok. And it also works for constexpr. For example:

auto* res = MY_VERIFY(impl.get_ptr(), "nullptr returned");
MY_VERIFY(sizeof(char) == 1, "Bad char size");

It works perfectly well for everything but structured bindings. :(

std::map<std::string, int> mymap;
for (const auto& [key, value] : mymap) {
  MY_VERIFY(value != 0, "Bad value for key %s", key.c_str());

doesn't compile because binding key is not captured to lambda closure.

Lambda implicit capture fails with variable declared from structured binding - here is more information.

I tried to solve problem, implementing it as a template function instead of lambda:

template <typename ResultType>
constexpr auto MY_VERIFY(ResultType&& _expr, const char* format, ...) noexcept -> DecayLvalueRef<decltype(_expr)> {
  if (!static_cast<bool>(_expr)) {
    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
    printf("\n");
    exit(-1);
  }
  return std::forward<decltype(_expr)>(_expr);
}

but in this case values for format string are evaluated before expr check, what is bad for performance reasons:

MY_VERIFY(sizeof(char) == 1, "Error value %d", SideEffect().GetValue());

In example above SideEffect instance would be created and GetValue() invoked even when expr is true.

I couldn't find solution, which worked in C++17. Any idea?

apple apple
  • 10,292
  • 2
  • 16
  • 36
Igor Semenov
  • 483
  • 5
  • 13

0 Answers0