Re-implementing lookup function using same logic as in std::ranges
Comment raised on !4520 (comment 9998415) by @graven:
ChatGPT offers two suggestions, the simplest of which should be applicable here:
concept HasFourMomentum =
requires (T t) { fourMomentum(t); } || // ADL + normal unqualified lookup
requires (T t) { LHCb::Event::fourMomentum(t); }; // explicit fallbackand a more complicated alternative, which is very interesting, but really suggests that the function lookup is completely re-implemented using the same style as used in std::ranges, using an explicit proper Customization Point Object (CPO) setup (see here, here). I'll only include it here for future reference - if we do this, it should be done as a dedicated MR across all accessor functions:
namespace detail {
struct four_momentum_fn {
template <class T>
constexpr auto operator()(T&& t) const
noexcept(noexcept(fourMomentum(std::forward<T>(t))))
-> decltype( fourMomentum(std::forward<T>(t)))
{
using SomeNamespace::fourMomentum; // bring fallback into scope
return fourMomentum(std::forward<T>(t)); // unqualified: ADL + using
}
};
inline constexpr four_momentum_fn four_momentum{};
}
template <typename T>
concept HasFourMomentum = requires (T t) { detail::four_momentum(t); };
// …and when you need to call it:
auto p = detail::four_momentum(obj);
which would imply that every time an ADL function is invoked and which follows the pattern using LHCb::Event::SomeFun; SomeFun(x) will have to be changed to LHCb::Event::SomeFun(x), where LHCb::Event::SomeFun is no longer a function, but the instance of an object which calls the relevant function which 'centralizes' the using and unqualified call, and also figures out any alternatives to call (eg. if a member function exists, call it)...