Info
-
Did you know that
using-declarator
can be used to manipulate the overload set? -
http://eel.is/c++draft/namespace.udecl#:name_hiding,using-declaration_and
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));
}
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}));
};
}
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) + ...);
};
}
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));
};
}
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) + ...);
};
}
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...) + ...); };
}
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);};
}