Skip to content

Latest commit

 

History

History
152 lines (115 loc) · 4.06 KB

329.md

File metadata and controls

152 lines (115 loc) · 4.06 KB
Info

Example

struct header { int type{}; };

int main() {
    std::cout << []<auto Ptr>(const auto& msg) {
        return msg.*Ptr;
    }.operator()<&header::type>(header{42});  // prints 42
}

https://godbolt.org/z/cabhaoec1

Puzzle

  • Can you implement a dispatch lambda expression which calls ::dispatch function based on header::type and msg::id?
struct [[gnu::packed]] header {
    int type{};
};

struct [[gnu::packed]] msg1 : header {
    static constexpr auto id = 1;
    int i{};
};

struct [[gnu::packed]] msg2 : header {
    static constexpr auto id = 2;
    float f{};
};

auto dispatch(std::ostream& out, const msg1& msg) { out << "msg1: " << msg.i; }
auto dispatch(std::ostream& out, const msg2& msg) { out << "msg2: " << msg.f; }

#include <https://raw.githubusercontent.com/boost-ext/ut/v1.1.9/include/boost/ut.hpp>

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

    constexpr auto dispatch = /* TODO */;

    "pointer to member dispatch not found"_test = [dispatch] {
        const auto msg = msg1{};
        const void* buffer = &msg;
        std::stringstream out{};

        dispatch.operator()<&header::type, msg1, msg2>(out, buffer);

        expect(std::empty(out.str()));
    };

    "pointer to member dispatch found msg1"_test = [dispatch] {
        const auto msg = msg1{msg1::id, 42};
        const void* buffer = &msg;
        std::stringstream out{};

        dispatch.operator()<&header::type, msg1, msg2>(out, buffer);

        expect(out.str() == std::string_view{"msg1: 42"});
    };

    "pointer to member dispatch found msg2"_test = [dispatch] {
        const auto msg = msg2{msg2::id, 4.2};
        const void* buffer = &msg;
        std::stringstream out{};

        dispatch.operator()<&header::type, msg1, msg2>(out, buffer);

        expect(out.str() == std::string_view{"msg2: 4.2"});
    };
}

https://godbolt.org/z/q7n71h97z

Solutions

constexpr auto dispatch = []<auto Type, typename... Msgs>(
                              auto& out, const auto& buffer) {
    const auto type = static_cast<const header*>(buffer)->*Type;
    (
        [&]() {
            switch (type) {
                case Msgs::id:
                    const auto& msg = *static_cast<const Msgs*>(buffer);
                    ::dispatch(out, msg);
                    break;
            }
        }(),
        ...);
};

https://godbolt.org/z/7PMv1GE98

constexpr auto dispatch = []<auto pm, class... Ts>(std::ostream& out,
                                                   const void* buffer) {
    const auto type = static_cast<const header*>(buffer)->*pm;

    std::variant<std::monostate, Ts...> v;
    (
        [&]() {
            if (type == Ts::id) {
                v = *static_cast<const Ts*>(buffer);
            }
        }(),
        ...);

    return std::visit(overload{[&](auto&& msg) { ::dispatch(out, msg); },
                               [](std::monostate) {}},
                      v);
};

https://godbolt.org/z/4Pz33K4Pq

constexpr auto dispatch = []<auto Ptr, class... MessageTypes>(
                              auto& out, auto buffer) -> void {
    const auto helper = [&]<class M>(const M* m) {
        if (m->*Ptr == M::id) {
            ::dispatch(out, (M)(*reinterpret_cast<const M*>(buffer)));
        }
    };
    (helper(reinterpret_cast<const MessageTypes*>(buffer)), ...);
};

https://godbolt.org/z/sYGdEjq5q

constexpr auto dispatch = [&]<auto Ptr, class... Ts>(std::stringstream& out,
                                                     const void* buffer) {
    ((reinterpret_cast<const header*>(buffer)->*Ptr == Ts::id &&
      (::dispatch(out, *reinterpret_cast<const Ts*>(buffer)), true)) ||
     ...);
};

https://godbolt.org/z/acvzx1re7