This question assumes familiarity with the customization point management technique tag_invoke
, introduced in P1895R0.
A customization point object can be defined according to P1895R0 as:
inline constexpr struct foo_cpo {
// simplified original by omitting noexcept forward and using auto arg
auto operator()(auto const &x) -> decltype( std::tag_invoke(*this, x) ) {
return std::tag_invoke(*this, x); // <--^-- here are the Niebloid
}
} foo;
But given the crux of this technique is to work with objects directly, and delegate any and all ADL to one and only agreed-upon identifier tag_invoke
, then it seems the same effects can be achieved by simply,
inline constexpr struct {
auto operator()(auto const &x) -> decltype( tag_invoke(*this, x) ) {
return tag_invoke(*this, x); // no Niebloid. directly ADL call tag_invoke
}
} foo;
For instance, the type erasure example from P1895R0, which is https://godbolt.org/z/3TvO4f, can be reimplemented without using the Niebloid at all: https://godbolt.org/z/dzqE7b. The code is the same as the original verbatim, modulo the definition of the Niebloid std::tag_invoke
and using the above ADL form for all customization points objects.
What is the requirement that the presence of Niebloid really satisfies for tag_invoke
?
I don't think it's strictly necessary for tag_invoke
itself to be a function object. But defining it as an object gives us a handy place to put a poison-pill overload should we decide that's necessary. And it's generally nice to have functions as first-class citizens that can be passed to higher-order functions. That's it, really.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With