- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我想知道在其他函数模板可见的情况下,是否可以让 ADL 选择在其中一个参数的类的命名空间(或其他一些明确定义的位置)中定义的函数模板。下面是一个激励人心的例子,虽然我知道该特定案例的解决方法(我在下面讨论),但这个问题总体上似乎是有道理的。
我认为避免使用友元声明而是将工作委托(delegate)给方法很酷,因此想出了
namespace n
{
struct a
{
auto swap(a& a2) -> void;
};
auto swap(a& a1, a& a2) -> void
{
a1.swap(a2);
}
}
auto main(void) -> int
{
n::a a1, a2;
using std::swap;
swap(a1,a2); // use case 1
n::swap(a1,a2); // use case 2
}
到目前为止,一切都很好,两个用例都工作正常,但后来,我添加了第二个类,它有自己的交换方法,并决定通过将独立交换转换为模板来节省样板:
namespace n
{
struct a
{
auto swap(a& a2) -> void;
};
struct b
{
auto swap(b& b2) -> void;
};
template<class T>
auto swap(T& t1, T& t2) -> void
{
t1.swap(t2);
}
}
auto main(void) -> int
{
n::a a1, a2;
using std::swap;
swap(a1,a2); // use case 1
n::swap(a1,a2); // use case 2
}
这里用例 1 中断,编译器提示 std::swap
不明确模板。如果预料到这个问题,可以定义 swap
函数而不是方法(它们通常是 friend ,因为它们替代了方法):
namespace n
{
struct a
{
friend auto swap(a& a1, a& a2) -> void;
};
struct b
{
friend auto swap(b& b1, b& b2) -> void;
};
}
现在一切正常,所以在 swap
的情况下记住使用友元函数而不是方法就足够了,但是一般情况呢?是否有任何 hack,无论多么肮脏,都可以让编译器明确选择 n::foo<a>
(或其他一些 foo<a>
在我们的控制下)在其他 template<class T> foo
的情况下是可见的,要么在全局命名空间中,要么因为某些 using
条款,特别是如果后者不是我们要修改的?
最佳答案
这里的罪魁祸首不仅仅是你写了using std::swap
, 但从根本上说,您提供了自己的不受限制的函数模板 swap
这将给出重载解析错误 std::swap
每当namespace std
在名称查找期间正在考虑(通过显式 using
指令,或通过 ADL)。
为了说明:只是省略了 using std::swap
在这种情况下会救你
auto main() -> int
{
n::a a1, a2;
swap(a1,a2); // use case 1
n::swap(a1,a2); // use case 2
}
但是假设你重构了你的类 a
和 b
进入类模板b<T>
和 b<T>
,并使用来自 namespace std
的模板参数调用它们(例如 std::string
),然后你会得到一个重载解析错误:
#include <iostream>
#include <string>
namespace n
{
template<class>
struct a /* as before */;
template<class>
struct b /* as before */;
}
auto main() -> int
{
n::a<std::string> a1, a2; // oops, ADL will look into namespace std
swap(a1,a2); // use case 1 (ERROR)
n::swap(a1,a2); // use case 2 (OK)
}
结论:如果您定义自己的 swap
版本与 std::swap
具有相同的签名(就重载决议而言),始终限定对它的调用以禁用 ADL。
提示:更好的是,不要偷懒,只需提供您自己的 swap
您自己的命名空间中每个类的函数(不是函数模板)。
另见 this Q&A其中解释了为什么提供自己的 begin
不是一个好主意的类似机制。和 end
模板并期望它们与 ADL 一起工作。
关于c++ - 如何让 ADL 更喜欢一个函数模板而不是另一个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34481998/
我是一名优秀的程序员,十分优秀!