2

I have this forwarding function, that may or may not throw, depending on what the arguments are:

template <std::size_t M>
constexpr void split_apply(auto f, auto&& ...a) // noexcept(?)
{
  // transforms provided tuple t into a tuple of N-element tuples
  constexpr auto split([]<std::size_t N>(auto&& t) noexcept requires (bool(N))
    {
      constexpr auto n(std::tuple_size_v<std::remove_cvref_t<decltype(t)>>);
      static_assert(n && !(n % N));
      return [&]<auto ...I>(std::index_sequence<I...>) noexcept
        {
          return std::make_tuple(
            [&]<auto ...J>(std::index_sequence<J...>) noexcept
            {
              constexpr auto K(N * I);
              return std::forward_as_tuple(std::get<K + J>(t)...);
            }(std::make_index_sequence<N + I - I>())...
          );
        }(std::make_index_sequence<n / N>());
    }
  );

  std::apply([&](auto&& ...t) noexcept(noexcept(
    (std::apply(f, std::forward<decltype(t)>(t)), ...)))
    {
      (std::apply(f, std::forward<decltype(t)>(t)), ...);
    },
    split.template operator()<M>(std::forward_as_tuple(a...))
  );
}

Since std::apply() does not have a noexcept specifier (a defect IMO), there probably should not be any here as well, but let's assume that it had one. How would I compute whether split_apply() throws for some provided arguments?

user1095108
  • 14,119
  • 9
  • 58
  • 116
  • I don't know if is of help, but `noexcept` is part of the signature, for instance given `void f() noexcept;`, then `static_assert(std::is_same_v);` passes, but `static_assert(std::is_same_v);` doesn't. Maybe you can `if constexpr` someway? – Enlico Sep 03 '21 at 13:38
  • 1
    *[`noexcept` operator](https://en.cppreference.com/w/cpp/language/noexcept) performs a compile-time check that returns true if an expression is declared to not throw any exceptions. It can be used within a function template's `noexcept` specifier to declare that the function will throw exceptions for some types but not others.* – Evg Sep 03 '21 at 13:43
  • I guess I need to clarify what I want, `std::apply()` does not have a `noexcept` specifier, but `std::invoke()` does. I'd like my function to have a (correct) `noexcept` specifier, just like `std::invoke()` does. Sometimes `std::invoke()` is `noexcept` and sometimes it is not. – user1095108 Sep 03 '21 at 13:47
  • What about `noexcept(std::is_nothrow_invocable_v)`? – Evg Sep 03 '21 at 13:50
  • @Evg yes, but the argument pack would have to be split somehow and the results ANDed. – user1095108 Sep 03 '21 at 13:56
  • you can find the answer [here](https://github.com/user1095108/generic/blob/master/invoke.hpp). – user1095108 Sep 03 '21 at 15:38

1 Answers1

0

The approach I took to solve this problem (in pseudo code):

constexpr bool is_nothrow_function(/*repeat arguments*/) noexcept
{
  return noexcept(
    // repeat function body
  );
}

This same approach can be taken to fix std::apply and an implementation is available on my GitHub page.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
user1095108
  • 14,119
  • 9
  • 58
  • 116