在std命名空间中重载(而不是特化)模板

8
这很严谨,但在C++03中,程序似乎不能(不是特化)重载位于std命名空间中的模板函数:详见此处提到的内容和comp.lang.c++.moderated上的长篇讨论
例如,以下代码是可以的:
namespace std
{
    template <>
    void swap (Foo & f, Foo & g)
    {
       // ...
    }
}

但是这不是(如果我理解正确的话...):
namespace std
{
    template <typename T>
    void swap (TempateFoo<T> & f, TempateFoo<T> & g)
    {
       // ...
    }
}

这在C++11中仍然适用吗?此外,这是否也适用于模板类(如std::hash),还是只适用于模板函数?
编辑:是否有任何标准库实现的示例,使得后者在实践中会破坏事情?如果没有,是否有特定的原因不允许像上面第二种情况中的重载?(理论上可能会发生什么问题?)

我认为你不能打开std命名空间来处理除了模板特化之外的其他事情。 - Nawaz
那么第二个例子仍然是非法的吗? - Stephen Lin
好的...我给这个打上了语言律师的标签,有原因的 :) - Stephen Lin
请记住,对于问题“是否有标准库实现的示例会在实践中破坏事物?”的答案可能是“没有”,但这并不意味着它将来不会破坏(如果标准不允许将此类添加到std命名空间)。 - Nawaz
@ChristianRau 是的,我现在意识到它是不同的。 - Stephen Lin
显示剩余3条评论
2个回答

8
在C++中不可能定义函数模板的部分特化,因此您的第二个示例定义的是一个重载而不是特化。由于标准只允许向命名空间std添加特化,因此您的重载是非法的。
“在C ++ 11中是否仍然如此?”是的。
“此外,这是否也适用于模板类(例如std :: hash),还是只适用于模板函数?”无论如何都不能重载类模板,只能重载函数。虽然应用相同的规则,但只有当特化依赖于用户定义的类型(即非标准类型)时,才可以特化类模板。
“为什么禁止像上面第二种情况的重载?(理论上会出现什么问题?)” 举一个例子,实现可能想要获取一个函数的地址,但如果您已经重载了该函数,则获取地址可能会导致模糊并且无法编译,这意味着您刚刚破坏了标准库中的有效代码。

好的,太棒了,最后那部分很有道理。 - Stephen Lin
使用自定义类型的偏特化(例如std :: hash)是可以的,还是只能进行完全特化? - Stephen Lin
1
如果部分特化取决于用户定义的类型,那么就可以使用,例如 std::hash<MyTemplate<T>> 是可以使用的,因为它依赖于用户定义的类型 MyTemplate<T> - Jonathan Wakely
酷,最后一部分(在用户定义类型上的std中的部分特化是可以的)是新的还是在C++03中也是如此? - Stephen Lin
“meaning non-standard” -- 我希望问题能够更明确 - Yakk - Adam Nevraumont
@Yakk,它没有被恰当地规定(这是一个缺陷),但当库条款(17-30)说“用户定义”时,它们意味着非标准的类型,所以std::string 不是一种用户定义类型。当语言条款说“用户定义”时,它们意味着不是基本的,所以std::string 是用户定义的。但在这个问题的上下文中,它指的是在标准中未定义的类型。 - Jonathan Wakely

6

n3376 17.6.4.2.1

如果未经指定,C++程序在向std命名空间或std命名空间中的任何命名空间添加声明或定义时行为是未定义的。程序只有在声明依赖于用户定义类型并且专门化满足原始模板的标准库要求且未被明确禁止时,才可以将任何标准库模板的专门化添加到std命名空间中。

17.6.4.2.2

如果声明了以下情况,则C++程序的行为是未定义的:

— 标准库类模板的任何成员函数的显式专门化,或

— 标准库类或类模板的任何成员函数模板的显式专门化,或

— 标准库类或类模板的任何成员类模板的显式或部分专门化。

程序只有在声明依赖于用户定义类型的名称且实例化满足原始模板的标准库要求时,才可以显式实例化标准库中定义的模板。


太好了,谢谢!不知道为什么不允许重载呢?显然这已经在讨论中出现了很多次,所以我想肯定有限制的原因。 - Stephen Lin
我暂时接受这个限制,但如果有人能够跟进并解释这个限制背后的原因,那就太好了 :) (我相信肯定有人已经向委员会提出过这个问题。) - Stephen Lin
3
添加一个重载函数可能会导致现有的无关调用使用该重载函数,而不是之前使用的任何其他函数。所谓的"无关"是指根本没有提及您自定义的类型。但特化函数不能做到这一点。 - n. m.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接