Skip to content

Latest commit

 

History

History
212 lines (169 loc) · 5.74 KB

240.md

File metadata and controls

212 lines (169 loc) · 5.74 KB
Info

Example

struct trade {};
struct add_order {};
struct transaction_end {};

struct i {
    constexpr virtual ~i() noexcept = default;
    constexpr virtual void on(const trade&) {}
    constexpr virtual void on(const add_order&) {}
    constexpr virtual void on(const transaction_end&) {}
};

struct impl1 : i {
  void on(const trade&) override {}
};

struct impl2 : i {
  using i::on;
  void on(const trade&) override {}
};

int main() {
    impl1 i1{};
    impl2 i2{};

    // via interface
    static_assert([](i& t) { return requires { t.on(trade{}); }; }(i1));
    static_assert([](i& t) { return requires { t.on(add_order{}); }; }(i1));
    static_assert([](i& t) { return requires { t.on(transaction_end{}); }; }(i1));

    // via concrete
    static_assert([](auto& t) { return requires { t.on(trade{}); }; }(i1));
    static_assert(not [](auto& t) { return requires { t.on(add_order{}); }; }(i1));
    static_assert(not [](auto& t) { return requires { t.on(transaction_end{}); }; }(i1));

    // via concrete with using::on
    static_assert([](auto& t) { return requires { t.on(trade{}); }; }(i2));
    static_assert([](auto& t) { return requires { t.on(add_order{}); }; }(i2));
    static_assert([](auto& t) { return requires { t.on(transaction_end{}); }; }(i2));
}

https://cpp.godbolt.org/z/1cWzP3cvM

Puzzle

  • Can you implement sum_prices which sums prices from given objects and messages?
struct trade {
  int price{};
};
struct order {
  int price{};
};

struct i {
  constexpr virtual ~i() noexcept = default;
  constexpr virtual auto price(const trade&) const -> int { return 1; }
  constexpr virtual auto price(const order&) const -> int { return 2; }
};

struct impl1 : i {
  constexpr auto price(const trade& t) const -> int override {
    return t.price;
  }
};

struct impl2 : i {
  using i::price;
  constexpr auto price(const trade& t) const -> int override { return t.price; }
};

auto sum_prices(...); // TODO

int main() {
  using namespace boost::ut;

  "sum prices"_test = [] {
    impl1 impl1{};
    i& i1 = impl1;
    impl2 impl2{};
    i& i2 = impl2;

    expect(0_i == sum_prices(impl1)());
    expect(0_i == sum_prices(impl1, i1)());
    expect(0_i == sum_prices(impl1, i1, impl2)());
    expect(0_i == sum_prices(impl1, i1, impl2, i2)());

    expect(42_i == sum_prices(impl1)(trade{.price = 42}));
    expect(84_i == sum_prices(impl1, i1)(trade{.price = 42}));
    expect(126_i == sum_prices(impl1, i1, impl2)(trade{.price = 42}));
    expect(168_i == sum_prices(impl1, i1, impl2, i2)(trade{.price = 42}));

    expect(42_i == sum_prices(impl1)(trade{.price = 42}, order{.price = 100}));
    expect(86_i == sum_prices(impl1, i1)(trade{.price = 42}, order{.price = 100}));
    expect(130_i == sum_prices(impl1, i1, impl2)(trade{.price = 42}, order{.price = 100}));
    expect(174_i == sum_prices(impl1, i1, impl2, i2)(trade{.price = 42}, order{.price = 100}));
  };
}

https://godbolt.org/z/zj7a4EvGx

Solutions

constexpr auto sum_prices(auto&&... is) {
    return [&] (auto&&... ts) {
        return ([&] (auto&& i) {
            return ([&] (auto&& t) {
                if constexpr (requires { i.price(t); }) {
                    return i.price(t);
                } else {
                    return 0;
                }
            }(ts) + ... + 0);
        }(is) + ...);
    };
}

https://godbolt.org/z/G7fdrT9v1

auto sum_prices(const auto&... interfaces) {
  constexpr auto get_price = [](const auto& interface, const auto& arg) {
    if constexpr (requires { interface.price(arg); }) {
      return interface.price(arg);
    } else {
      return 0;
    }
  };
  return [&](const auto&... args) {
    auto sum = [&](const auto& interface) {
      return (0 + ... + decltype(get_price){}(interface, args));
    };
    return (0 + ... + sum(interfaces));
  };
}

https://godbolt.org/z/oW1Gz8a5W

auto sum_prices(const auto&... interfaces) {
    return [&](const auto&... messages) {
        const auto apply_interface = [&](const auto& interface) {
            const auto message_price = [&](const auto& message) {
                if constexpr (requires { interface.price(message); }) {
                    return interface.price(message);
                } else {
                    return 0;
                }
            };

            return (message_price(messages) + ... + 0);
        };

        return (apply_interface(interfaces) + ...);
    };
}

https://godbolt.org/z/8dcvK5vEM

namespace detail {

[[nodiscard]] constexpr auto extract_price_if_available(const auto& impl, const auto value) {
    if constexpr (requires { impl.price(value); }) {
        return impl.price(value);
    } else {
        return 0;
    }
}

[[nodiscard]] constexpr auto sum_for_impl(const auto& impl, const auto&... vals) {
    return (0 + ... + extract_price_if_available(impl, vals));
}

}

auto sum_prices(const auto &... impls) {
    return [&](const auto&... values) {
        return (detail::sum_for_impl(impls, values...) + ...); };
}

https://godbolt.org/z/r5ns3b53E

template<class ... Proc>
auto sum_prices(Proc&& ... proc) {
    auto callPrice = [](auto&& pr, auto obj) {
        if constexpr (requires { pr.price(obj); }) return pr.price(obj); else return 0;
    };
    auto sumProcPrice = [callPrice, &proc...](auto obj) { return ( callPrice(proc, obj) + ...);};
    return [sumProcPrice](auto ... objs) { return (sumProcPrice(objs) + ...+ 0);};
}

https://godbolt.org/z/dTP3ahjMs