182.md

September 9, 2022 ยท View on GitHub

Info

  • Did you know about the proposal to add Non-terminal variadic template parameters?

Example

template<class... Ts, class T>
auto foo(Ts..., T t) { return t; }
int main() {
  std::cout << foo(1); // prints 1
  std::cout << foo(1, 2, 3, 4); // prints 4
  std::cout << foo(); // compilation error
}

https://godbolt.org/z/z9jvd4vhx

Puzzle

  • [NTVTP] Can you implement last_using_{get,apply,inplace_lambda} functions which will return the last element of given tuple?
/* TODO */
constexpr auto last_using_get(...);
constexpr auto last_using_apply(...);
constexpr auto last_using_inplace_lambda(...);

int main() {
  "tuple - get last"_test = [] {
    should("return the only element") = []{
      auto tuple = std::tuple{42};
      42_i == last_using_get(tuple) and
      42_i == last_using_apply(tuple) and
      42_i == last_using_inplace_lambda(tuple);
    };
    should("return the last element with same types") = [] {
      auto tuple = std::tuple{4l, 2l, 42l};
      42_l == last_using_get(tuple) and
      42_l == last_using_apply(tuple) and
      42_l == last_using_inplace_lambda(tuple);
    };
    should("return the last element with differen types") = [] {
      auto tuple = std::tuple{1, 2.0, "3", 4ul};
      4_ul == last_using_get(tuple) and
      4_ul == last_using_apply(tuple) and
      4_ul == last_using_inplace_lambda(tuple);
    };
  };
}

https://godbolt.org/z/111hzT

Solutions

constexpr auto last_using_get(const auto& tuple) noexcept
{
    using tuple_type = std::decay_t<decltype(tuple)>;
    return std::get<std::tuple_size_v<tuple_type> - 1>(tuple);
}
constexpr auto last_using_apply(const auto& tuple)
{
    return std::apply([](const auto... args) { return (args, ...); }, tuple);
}
constexpr auto last_using_inplace_lambda(const auto& tuple) {
    return [&](){
        return last_using_get(tuple);
    }();
}

https://godbolt.org/z/1P3Mcj

template <typename TTuple>
constexpr auto last_using_get(TTuple&& t) -> decltype(auto) {
    constexpr auto size = std::tuple_size_v<std::remove_reference_t<TTuple>>;
    return std::get<size-1>(std::forward<TTuple>(t));
}

template <typename TTuple>
constexpr auto last_using_apply(TTuple&& t) -> decltype(auto) {
    return std::apply(
        [](auto&&...args) -> decltype(auto) {
            return (std::forward<decltype(args)>(args), ...);
        },
        std::forward<TTuple>(t));
}

template <typename TTuple>
constexpr auto last_using_inplace_lambda(TTuple&& t) -> decltype(auto) {
    constexpr auto size = std::tuple_size_v<std::remove_reference_t<TTuple>>;
    return [&] <auto... I> (std::index_sequence<I...>) -> decltype(auto) {
        return std::get<(I,...)>(std::forward<TTuple>(t));
    }(std::make_index_sequence<size>{});
}

https://godbolt.org/z/c5PzYK