当其中一个函数实际上是函数对象时,修复或替代 ADL

问题描述

在下面的代码中,命名空间 S 中的独立组件有自己的 BigSmall 类型定义,以及一个 split 函数来拆分一个 { {1}} 到 Big 的集合中。

Small 还提供了另一个函数 S,它利用了 work,并且旨在由 split 本身以及其他依赖组件使用,例如命名空间 S 中的一个,假定它们提供自己对 DBig 的定义以及自己对 Small 的定义,这些定义将通过 ADL 进行标识。¹

split

嗯,实际上 #include <iostream> #include <string> #include <utility> #include <vector> namespace S /* standalone */ { struct Big{}; struct Small{}; std::vector<Small> split(Big b) { std::cout << "S" << std::endl; return {/* use b to make output */}; } template<typename BigT> void work(BigT/* acutally this is a template class with `BigT` as a template paramter*/ x) { split(x); // correspondingly `split` is not applied on `x` but on the `BigT` which is part of it // a lot of complex stuff } } namespace D /* dependent on standalone */ { struct Big{}; struct Small{}; std::vector<Small> split(Big b) { std::cout << "D" << std::endl; return {/* use b to make output */}; } } int main() { S::Big line1{}; D::Big line2{}; S::work(line1); // uses S::split S::work(line2); // uses D::split } 一个函数对象,而不是一个函数²,

S::split

所以 ADL 不起作用。

对于如何满足这些需求有什么建议吗?

评论中可以看出,Niebloids 和/或 namespace S { struct Split { std::vector<Small> operator()(Big) const { std::cout << "S" << std::endl; return {}; } } split; } 可能代表了我的问题的答案。我真的很想更多地了解这些概念。

就目前而言,我对 Niebloids 的理解(我正在阅读 this blog from Eric Niebler)是它们是(当它们在范围内时)阻止 ADL 的函数对象,因此将所有函数调用“集中”到不合格的与 niebloid 同名的自由函数;然而,他们的 tag_invoke 依赖 ADL 将调用转发到适当的free 函数。因此,在我的示例代码中,operator()一个函数对象和 S::split一个自由函数间的对比似乎无法由 niebloids 解决,除非我使 D::split 成为一个自由函数(其中case ADL 在我的简单场景中就足够了)。


¹ 最初在 S::splitwork 中都定义了 S,上面的代码是我尝试重构的,在此期间我遇到了所描述的问题。

² 这样做的原因是 DS::split 的多个上下文中使用,它有一些 S 的重载,最重要的是,它经常作为对象传递,非常方便。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)