Skip to content

Fix the noexcept specification of xt::apply - #2948

Open
gouarin wants to merge 1 commit into
xtensor-stack:masterfrom
gouarin:fix-apply-noexcept
Open

gouarin wants to merge 1 commit into
xtensor-stack:masterfrom
gouarin:fix-apply-noexcept

Conversation

@gouarin

@gouarin gouarin commented Oct 29, 2026

Copy link
Copy Markdown
Member

Checklist

  • The title and commit message(s) are descriptive.
  • Small commits made to fix your PR have been squashed to avoid history pollution.
  • Tests have been added for new features or bug fixes.
  • API of new functions and classes are documented (no public API changes).

Description

xt::apply is declared noexcept(noexcept(func(std::get<0>(s)))), which only looks at the call on the first tuple element. The body also holds an XTENSOR_ASSERT on the index. Both cases call std::terminate instead of propagating the exception:

auto f = [](int i) noexcept { return i; };
xt::apply<int>(5, f, std::make_tuple(1, 2, 3));  // index out of range, with XTENSOR_ENABLE_ASSERT

struct g_t
{
    int operator()(int i) const noexcept { return i; }
    int operator()(const std::string&) const { throw std::runtime_error("g"); }
};
xt::apply<int>(1, g_t{}, std::make_tuple(1, std::string("a")));  // noexcept only looked at g_t{}(1)

GCC reports the first one with -Wterminate and clang with -Wexceptions in the assert builds.

The specification is now detail::is_nothrow_apply_v: the functor on every element converted to R, the R{} fallback, and the index check, through a new detail::assert_can_throw constant. xutils.hpp now includes xexception.hpp, since it uses XTENSOR_ASSERT.

utils.apply_propagates_exception and utils.apply_out_of_range terminate on master and pass with the fix. The noexcept check in utils.apply now expects false in assert builds.

xt::apply was declared noexcept(noexcept(func(std::get<0>(s)))), which
only looks at the call on the first tuple element. Its body also holds an
XTENSOR_ASSERT on the index, which throws when XTENSOR_ENABLE_ASSERT is
defined. An out-of-range index, or a functor that throws for another
element of the tuple, therefore called std::terminate instead of
propagating the exception. GCC reports it with -Wterminate and clang with
-Wexceptions.

The specification is now detail::is_nothrow_apply_v, which checks every
call the body can make: the functor on each tuple element converted to R,
the R{} fallback, and the index assertion. The new
xt::detail::assert_can_throw constant tells whether a failing
XTENSOR_ASSERT throws. xutils.hpp now includes xexception.hpp, since it
uses XTENSOR_ASSERT and XTENSOR_THROW.
@codspeed

codspeed Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

1 warning

⚠️ Unable to measure the execution of 1 benchmark

This benchmark measured no execution time, so its result is not comparable and counts as unchanged. This usually happens when the compiler removes the code under test.

Prevent compiler optimizations

See affected benchmarks

✅ 255 untouched benchmarks


Comparing gouarin:fix-apply-noexcept (25547ad) with master (57f3d07)

Open in CodSpeed

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant