正如Litb所说,ADL在其工作的地方是优越的,这基本上是从调用参数推导模板参数的时候:
#include <iostream>
namespace arithmetic {
template <class T, class S>
T mul(const T& x, const S& y) { return x * y; }
}
namespace ns {
class Identity {};
// this is how we write a special mul
template <class T>
T mul(const T& x, const Identity&) {
std::cout << "ADL works!\n";
return x;
}
// this is just for illustration, so that the default mul compiles
int operator*(int x, const Identity&) {
std::cout << "No ADL!\n";
return x;
}
}
int main() {
using arithmetic::mul;
std::cout << mul(3, ns::Identity()) << "\n";
std::cout << arithmetic::mul(5, ns::Identity());
}
输出:
ADL works!
3
No ADL!
5
重载+adl通过部分专门化函数模板来实现您想要的效果
arithmetic::mul
对于
S = ns::Identity
. 但它确实依赖于呼叫方以允许ADL的方式呼叫它,这就是为什么你从不打电话的原因。
std::swap
明确地。
所以问题是,您希望库的用户必须为什么部分地专门化您的函数模板?如果他们要专门化类型(通常是算法模板的情况),请使用ADL。如果他们要专门化整型模板参数,比如在您的示例中,那么我猜您必须委托给一个类。但我通常不希望第三方定义乘3应该做什么-我的库会做。
全部的
整数。我可以合理地期望第三方定义
octonion
会的。
想想看,求幂可能是一个更好的例子,因为我
算术::mul
令人困惑的类似于
operator*
所以没有必要专门化
mul
在我的例子中。然后我将为第一个参数专门化/adl重载,因为“任何事物的力量的标识都是标识”。不过,希望你能理解。
我认为ADL有一个缺点——它有效地扁平了名称空间。如果我想使用ADL“实现”两者
arithmetic::sub
和
sandwich::sub
为了我的课,我可能会有麻烦。我不知道专家们对此有什么看法。
我的意思是:
namespace arithmetic {
// subtraction, returns the difference of lhs and rhs
template<typename T>
const T sub(const T&lhs, const T&rhs) { return lhs - rhs; }
}
namespace sandwich {
// sandwich factory, returns a baguette containing lhs and rhs
template<typename SandwichFilling>
const Baguette sub(const SandwichFilling&lhs, const SandwichFilling&rhs) {
// does something or other
}
}
现在,我有一种类型
ns::HeapOfHam
. 我想利用std::swap-style adl编写我自己的算术::sub实现:
namespace ns {
HeapOfHam sub(const HeapOfHam &lhs, const HeapOfHam &rhs) {
assert(lhs.size >= rhs.size && "No such thing as negative ham!");
return HeapOfHam(lhs.size - rhs.size);
}
}
我还想利用std::swap-style adl编写自己的sandwich::sub实现:
namespace ns {
const sandwich::Baguette sub(const HeapOfHam &lhs, const HeapOfHam &rhs) {
// create a baguette, and put *two* heaps of ham in it, more efficiently
// than the default implementation could because of some special
// property of heaps of ham.
}
}
等一下。我不能那样做,是吗?具有相同参数和不同返回类型的不同命名空间中的两个不同函数:通常不是问题,这就是命名空间的用途。但我不能告诉他们两个。可能我错过了一些非常明显的东西。
顺便说一句,在这种情况下,我可以完全专业化
算术::子
和
三明治::子
.打电话的人会
using
一个或另一个,得到正确的功能。不过,最初的问题是关于部分专门化的,所以如果没有我将heapofham作为类模板,我们可以假装专门化不是一个选项吗?