12

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?

sehe
  • 374,641
  • 47
  • 450
  • 633
Nick
  • 931
  • 6
  • 17
  • There is no niebloid anywhere here. `std::tag_invoke` is _not_ a niebloid. – Barry Sep 11 '20 at 13:42
  • 1
    Barry, the distinction between what cppreference.com means by "niebloid" and what the standard calls a "customization point object" is interesting only Committee wonks, I think. I've given up trying to draw a distinction, and I think eventually the Committee will cave and call these things objects as they really are. It's all the same. – Eric Niebler Sep 11 '20 at 16:14

1 Answers1

12

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.

Eric Niebler
  • 5,927
  • 2
  • 29
  • 43
  • hey thanks! you mean to catch things like this: https://godbolt.org/z/nr7h3j ? – Nick Sep 10 '20 at 22:10
  • what is the use case to pass std::tag_invoke itself around? wouldn't we just pass CPOs? or rather, even if we passed std::tag_invoke, wouldn't we need to also pass CPOs anyway? – Nick Sep 10 '20 at 22:11
  • 3
    Nick, yes, a poison pill overload helps in cases of accidental hijacking like that. As for _why_ someone would pass `tag_invoke` to a higher-order function, I don't know, but my imagination is pretty limited. – Eric Niebler Sep 11 '20 at 16:17