如何解决当其中一个函数实际上是函数对象时,修复或替代 ADL
在下面的代码中,命名空间 S
中的独立组件有自己的 Big
和 Small
类型定义,以及一个 split
函数来拆分一个 { {1}} 到 Big
的集合中。
Small
还提供了另一个函数 S
,它利用了 work
,并且旨在由 split
本身以及其他依赖组件使用,例如命名空间 S
中的一个,假定它们提供自己对 D
和 Big
的定义以及自己对 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::split
和 work
中都定义了 S
,上面的代码是我尝试重构的,在此期间我遇到了所描述的问题。
² 这样做的原因是 D
在 S::split
的多个上下文中使用,它有一些 S
的重载,最重要的是,它经常作为对象传递,非常方便。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。