Example
[[nodiscard]] constexpr auto if_hell(bool c1, bool c2) {
if (c1) {
if (c2) {
return true;
} else {
throw;
}
}
// ...
return false;
}
static_assert(not if_hell(false, false));
static_assert(not if_hell(false, true));
assert(throws([]{ if_hell(true, false)); }));
static_assert(if_hell(true, true));
[[nodiscard]] constexpr auto if_heaven(bool c1, bool c2) {
if (not c1) {
return false;
}
if (not c2) {
throw;
}
// ...
return true;
}
static_assert(not if_heaven(false, false));
static_assert(not if_heaven(false, true));
assert(throws([]{ if_heaven(true, false)); }));
static_assert(if_heaven(true, true));
Puzzle
- Can you refactor function
foo
to avoid if/else hell anti-pattern?
#include <optional>
#include <stdexcept>
// TODO refactor foo to avoid if/else hell anti-pattern
[[nodiscard]] constexpr auto foo(auto trigger, bool is_buy, int price, int quantity) -> std::optional<int> {
if (is_buy) {
if (price > 0) {
if (quantity > 0) {
const auto filled = trigger(price, quantity);
if (filled > 0) {
return filled;
} else {
return std::nullopt;
}
} else {
return std::nullopt;
}
} else {
return std::nullopt;
}
} else {
throw std::runtime_error{"not is_buy!"};
}
return std::nullopt;
}
#include <https://raw.githubusercontent.com/boost-experimental/ut/master/include/boost/ut.hpp>
#include <tuple>
int main() {
using namespace boost::ut;
"foo"_test = [] {
expect(throws([]{std::ignore = foo([](auto...) { return 0; }, false, 0, 0);}));
expect(not foo([](auto...) { return 0; }, true, 0, 0));
expect(not foo([](auto...) { return 0; }, true, 10, 0));
expect(not foo([](auto...) { return 0; }, true, 10, 10));
expect(not foo([](auto...) { return 0; }, true, 10, 10));
expect(1 == foo([](auto...) { return 1; }, true, 10, 10));
expect(42 == foo([](auto...) { return 42; }, true, 100, 1000));
};
}
Solutions
[[nodiscard]] constexpr auto foo(auto trigger, bool is_buy, int price, int quantity) -> std::optional<int> {
if (not is_buy) {
throw std::runtime_error{"not is_buy!"};
}
if (price <= 0 or quantity <= 0) {
return std::nullopt;
}
const auto filled = trigger(price, quantity);
if (filled > 0) {
return filled;
} else {
return std::nullopt;
}
}
[[nodiscard]] constexpr auto foo(auto trigger, bool is_buy, int price, int quantity) -> std::optional<int>
{
if (not is_buy)
{
throw std::runtime_error{"not is_buy!"};
}
if ((price > 0) && (quantity > 0))
{
const auto filled = trigger(price, quantity);
if (filled > 0)
{
return filled;
}
}
return std::nullopt;
}
[[nodiscard]] constexpr auto foo(auto trigger, bool is_buy, int price, int quantity) -> std::optional<int> {
if (not is_buy) {
throw std::runtime_error{"not is_buy!"};
}
if (price <= 0 || quantity <= 0)
{
return std::nullopt;
}
const auto filled = trigger(price, quantity);
if (filled <= 0) {
return std::nullopt;
}
return filled;
}
[[nodiscard]] constexpr auto foo(auto trigger, bool is_buy, int price, int quantity) -> std::optional<int> {
if (not is_buy) {
throw std::runtime_error{"not is_buy!"};
}
if (price <= 0 or quantity <= 0) {
return std::nullopt;
}
if (const auto filled = trigger(price, quantity); filled) {
return filled;
}
return std::nullopt;
}
[[nodiscard]] constexpr auto foo(auto trigger, bool is_buy, int price, int quantity) -> std::optional<int> {
if (not is_buy)
throw std::runtime_error{"not is_buy!"};
if (price <= 0 or quantity <=0)
return std::nullopt;
const auto filled = trigger(price,quantity);
if( trigger(price,quantity)>0)
return filled;
return std::nullopt;
[[nodiscard]] constexpr auto foo(auto trigger, bool is_buy, int price, int quantity) -> std::optional<int> {
if (not is_buy) {
throw std::runtime_error{"not is_buy!"};
}
if (price <= 0 or quantity <= 0) {
return std::nullopt;
}
const auto filled = trigger(price, quantity);
return filled > 0 ? std::optional{filled} : std::nullopt;
[[nodiscard]] constexpr auto foo(auto trigger, bool is_buy, int price,
int quantity) -> std::optional<int> {
if (!is_buy) {
throw std::runtime_error{"not is_buy!"};
}
if (int filled;
price > 0 && quantity > 0 && (filled = trigger(price, quantity)) > 0) {
return filled;
}
return std::nullopt;
}
[[nodiscard]] constexpr auto foo(auto trigger, bool is_buy, int price, int quantity) -> std::optional<int> {
if (!is_buy){
throw std::runtime_error{"not is_buy!"};
}
decltype(trigger(std::declval<int>(), std::declval<int>())) filled;
if (price > 0 && quantity > 0 && (filled = trigger(price, quantity)) > 0) {
return filled;
}
return std::nullopt;
}