我们从一个简单的number
类加法方法开始:
class number {
int num;
public:
number(int num = 0): num(num) {}
operator int() const { return num; }
};
number add(number t1, number t2) {
return t1 + t2;
}
int main() {
auto result1 = add(1, 2); // auto-casting, works fine
}
现在我们想把number
变成一个模板类:
template<class T>
class number {
T num;
public:
number(T num = 0): num(num) {}
operator T() const { return num; }
};
template<class T>
number<T> add(number<T> t1, number<T> t2) {
return t1 + t2;
}
基于理论上的CTAD,我们尝试调用与简单非模板化版本相同的add
方法:
int main() {
number a = 3; // works, using CTAD
// auto result1 = add(1, 2); // <== what we wish for, but can't find method
// auto result2 = add(a, 2); // this also doesn't work, no ADL here :(
auto result3 = add<int>(1, 2); // this works, but is not what we wish
}
请注意,如果
add
是一个友元函数,那么只要其中一个参数是number
,根据ADL,就可以调用它。template<class T>
class number {
T num;
public:
number(T num = 0): num(num) {}
operator T() const { return num; }
friend number add(number t1, number t2) {
return t1 + t2;
}
};
int main() {
number a = 3; // works, using CTAD
auto result1 = add(a, 2); // works, based on ADL
// auto result2 = add(1, 2); // still doesn't work, no ADL here :(
}
有什么建议可以让模板类在调用 add 函数时自动转换类型,从而与非模板类类似?注意:对于像 add 这样的通用函数具有这样的自动转换可能是个错误的想法,但假设该方法非常具体,例如 doSomethingWithNumbers。
add(1.0, 2.0)
会调用一个与1.0
和2.0
类型完全不相关联的函数呢?编译器为什么会想到查找number
命名空间中的add
函数作为一种可能性,特别是它在另一个命名空间中? - Nicol Bolasadd
的定义不算在内。在模板定义内部,模板名称不带模板参数也作为当前实例化模板的名称。 - Nicol Bolasadd(number{1}, number{2})
可以正常工作,并且它使用了 CTAD。 - bolovrequires
以将其限制在正确的范围内。看起来这是唯一实现这一点的方法。 - Amir Kirsh