为什么 tag_invoke 模式需要 Niebloid std::tag_invoke?
Why does tag_invoke pattern need the Niebloid std::tag_invoke at all?
此问题假定您熟悉 P1895R0 中介绍的自定义点管理技术 tag_invoke
。
自定义点对象可根据P1895R0定义为:
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;
但鉴于此技术的关键是直接使用对象,并将所有 ADL 委托给一个且唯一商定的标识符 tag_invoke
,那么它 似乎 可以通过简单地实现相同的效果,
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;
例如P1895R0的类型擦除示例,即https://godbolt.org/z/3TvO4f, can be reimplemented without using the Niebloid at all: https://godbolt.org/z/dzqE7b。代码与原始逐字相同,对 Niebloid std::tag_invoke
的定义取模并对所有自定义点对象使用上述 ADL 形式。
Niebloid的存在真正满足tag_invoke
的要求是什么?
我不认为 tag_invoke
本身必须是一个函数对象。但是将它定义为一个对象给了我们一个方便的地方来放置 poison-pill 重载,如果我们认为这是必要的。拥有可以传递给 higher-order 函数的 first-class 公民函数通常很好。就是这样,真的。
此问题假定您熟悉 P1895R0 中介绍的自定义点管理技术 tag_invoke
。
自定义点对象可根据P1895R0定义为:
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;
但鉴于此技术的关键是直接使用对象,并将所有 ADL 委托给一个且唯一商定的标识符 tag_invoke
,那么它 似乎 可以通过简单地实现相同的效果,
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;
例如P1895R0的类型擦除示例,即https://godbolt.org/z/3TvO4f, can be reimplemented without using the Niebloid at all: https://godbolt.org/z/dzqE7b。代码与原始逐字相同,对 Niebloid std::tag_invoke
的定义取模并对所有自定义点对象使用上述 ADL 形式。
Niebloid的存在真正满足tag_invoke
的要求是什么?
我不认为 tag_invoke
本身必须是一个函数对象。但是将它定义为一个对象给了我们一个方便的地方来放置 poison-pill 重载,如果我们认为这是必要的。拥有可以传递给 higher-order 函数的 first-class 公民函数通常很好。就是这样,真的。