CppCoreGuidelines T.47 高可见度的未限定的模板,避免用常见名字
15 September 2023
“Avoid highly visible unconstrained templates with common names”
理由
模板的未限定的参数可以匹配任何东西,所以会比特定类型的参数的模板更容易匹配到。在用了 ADL 的时候,会很讨厌、很危险。常见名字使得问题更糟糕。
例子
namespace Bad { struct S { int m; }; template<typename T1, typename T2> bool operator==(T1, T2) { cout << "Bad\n"; return true; } } namespace T0 { bool operator==(int, Bad::S) { cout << "T0\n"; return true; } // compare to int void test() { Bad::S bad{ 1 }; vector<int> v(10); bool b = 1 == bad; // T0 bool b2 = v.size() == bad; // Bad } } int main() { T0::test(); }
T0 Bad
这里, Bad
中的 ==
引起了问题。但是你能在真实代码中发现这个问题吗?问题是这样的, v.size()
返回一个无符号整型,所以如果要用 T0
中的 ==
操作符,需要一次类型转换。而 Bad
中的 ==
不需要类型转换。像标准库中的迭代器等真实类型就有这种反社会倾向。
注意
如果你在同一个名字空间中定义一个未限定的模板,ADL 会发现这个未定义的模板(正如例子中所发生的)。因为这个模板的可见度更高。
注意
本来不应该有这条规则,但是 C++ 标准委员会成员不同意把未定义的模板排除在 ADL 之外。
很遗憾,这会导致很多误报。而且标准库也很大程度上违反此规则,把很多未限定的模板和类型放在单独的 std
名字空间。
强化
标记在同一个名字空间里有具体类型又有未限定模板的情况(可能直到我们有 concepts 之后才可以做到)