Skip to content

Latest commit

 

History

History
181 lines (141 loc) · 3.76 KB

267.md

File metadata and controls

181 lines (141 loc) · 3.76 KB
Info

Example

#include <utility>

int main() {
    std::unreachable();
    return 42; // invokes undefined behavior
}

https://godbolt.org/z/z776vY8EP

Puzzle

  • Can you implement switch_id which marks call with unknown id (id != Ids...) as unreachable?
template<auto Unreachable, auto... Ids>
constexpr auto switch_id(auto id); // TODO

int main(){
    using namespace boost::ut;
    expect(1_i == switch_id<[] { std::unreachable(); }, 1, 2, 4>(1));
    expect(2_i == switch_id<[] { std::unreachable(); }, 1, 2, 4>(2));
    expect(throws<std::runtime_error>([] { switch_id<[] { throw std::runtime_error{""}; }, 1, 2, 4>(3); }));
    expect(4_i == switch_id<[] { std::unreachable(); }, 1, 2, 4>(4));
}

https://godbolt.org/z/z3bP6dsPx

Solutions

template<auto Unreachable, auto... Ids>
constexpr auto switch_id(auto id) {
  if (((id != Ids) and ...)) {
    Unreachable();
  }
  return id;
}

https://godbolt.org/z/EefvGeGbz

constexpr auto compare(const auto elem, const auto id, auto& found_it)
{
    if(elem == id){ found_it = true; };
}

template<auto Unreachable, auto...List>
constexpr auto switch_id(auto id)
{
    auto found_it = false;
    auto list_tuple = std::make_tuple(List...);
    std::apply([&found_it,id](auto&&... elem) {((compare(elem,id,found_it)), ...);}, list_tuple);
    if( !found_it ){ Unreachable(); }
    return id;
};

https://godbolt.org/z/cfh6bq7Wo

template<auto... Ids>
constexpr auto id_does_not_exist = [](const auto id){
    return ((id != Ids) and ...);
};


template<auto Unreachable, auto... Ids>
constexpr auto switch_id(auto id){
    if(id_does_not_exist<Ids...>(id)){
        Unreachable();
    }
    return id;
}

https://godbolt.org/z/os1aTGq7b

template<auto Unreachable, auto...Ids>
constexpr auto switch_id(auto id) {
    std::vector ids{Ids...};
    if (std::find(std::begin(ids), std::end(ids), id) == std::end(ids)) {
        Unreachable();
    }

    return id;
}

https://godbolt.org/z/c6q1z76je

template<auto Unreachable, auto...IDs>
constexpr auto switch_id(auto id) {
  std::array<int, sizeof...(IDs)> a{IDs...};
  if (std::find(std::cbegin(a), std::cend(a), id) == std::cend(a)) {
   Unreachable();
  }
  return id;
};

https://godbolt.org/z/j38M17Erx

template<auto Unreachable>
auto switch_id(auto id)
{
    Unreachable();
    return std::declval<decltype(id)>();
}

template<auto Unreachable, auto Car, auto... Cdr>
auto switch_id(auto id)
{
    if (id == Car)
        return id;
    else
        return switch_id<Unreachable, Cdr...>(id);
}

https://godbolt.org/z/3q7nhaGeb

template<auto Unreachable, auto...Ids>
constexpr auto switch_id(auto id) {
    std::common_type_t<decltype(Ids)...> result;
    if ( ((id==Ids ? (result=id, true) : false) || ...) )
        Unreachable();
    return result;
}

https://godbolt.org/z/eaKqjq74E

template<auto Unreachable, auto... Ids>
constexpr auto switch_id(auto id){
    constexpr std::array<decltype(id),sizeof...(Ids)> ids = {{ Ids ... }};
    if (std::binary_search(ids.begin(), ids.end(), id)) return id;
    Unreachable();
    return id;
};

https://godbolt.org/z/66KWPxMxb

namespace detail {

[[nodiscard]] constexpr auto is_valid_id(const auto id, const auto... ids) {
    return (... and (id == ids));
}

}

template <auto Unreachable, auto... Ids>
constexpr auto switch_id(const auto id) {
    if (not detail::is_valid_id(id, Ids...)) {
        Unreachable();
    }

    return id;
}

https://godbolt.org/z/ojsPerYTP