Sto*_*ica 8 c++ template-specialization
我遇到了一个有趣的观点,我无法解释或找到解释.考虑以下模板定义(使用mingw g ++ 4.6.2编译):
template <typename T, typename S>
class Foo
{
public:
void f(){}
void g(){}
};
Run Code Online (Sandbox Code Playgroud)
如果我们想要,我们可以完全专注于任何单一成员函数:
template <>
void Foo<char,int>::f() {}
Run Code Online (Sandbox Code Playgroud)
但部分特化失败,"无效使用不完整类型'类Foo <...>'"错误:
template <typename T, typename S>
void Foo<T,S*>::f()
{
}
template <typename T>
void Foo<T,int>::f()
{
}
Run Code Online (Sandbox Code Playgroud)
我无法弄清楚原因.这是一个有意识的设计决策,以避免一些我无法预见的问题?这是疏忽吗?
提前致谢.
部分特化的概念仅存在于类模板(由§14.5.5描述)和成员模板(即模板类的成员本身是模板函数,由§14.5.5.3/ 2描述).它不存在于类模板的普通成员中,也不存在于函数模板中 - 仅仅因为它没有被标准描述.
现在,您可能会认为通过给出成员函数的部分特化的定义,例如
template <typename T>
void Foo<T,int>::f()
{ }
Run Code Online (Sandbox Code Playgroud)
你隐式定义了类模板的部分特化:Foo<T,int>.然而,这是明确的标准排除:
(§14.5.5/ 2)每个类模板部分特化是一个不同的模板,应为模板部分特化的成员提供定义(14.5.5.3).
(§14.5.5.3/ 1)[...]类模板部分特化的成员与主模板的成员无关.应定义以需要定义的方式使用的类模板部分特化成员; 主模板成员的定义从不用作类模板部分特化的成员的定义.[...]
后者意味着不可能通过简单地给出其成员之一的定义来隐式定义部分特化:该成员的存在不会遵循主要模板的定义,因此定义它等同于定义成员未声明的函数,这是不允许的(即使是非模板类).
另一方面,类模板的成员函数存在显式特化(或完全特化,如您所称)的概念.标准明确描述:
(§14.7.3/ 1)以下任何一种明确的专门化:
[...]
- 类模板的成员函数
[...]
可以由模板<>引入的声明声明; [...]
§14.7.3/ 14描述了细节:
(§14.7.3/ 14)类模板的成员或成员模板可以显式专门用于类模板的给定隐式实例化,即使在类模板定义中定义了成员或成员模板.[...]
因此,对于成员的显式特化,类模板的其余部分的实例化是隐式工作的 - 它是从主模板定义派生的,或者是定义的任何部分特化.
我试图从标准中找到一个简洁的引用,但我不认为有一个.事实是,没有模板函数的部分特化(或者,就此而言,模板别名).只有类模板可以具有部分特化.
让我们忘记模板一秒钟.在C++中,类名和函数名之间存在很大差异.给定范围内只能有一个类的定义.(你可以有各种声明,但它们都引用了One True Class.)所以这个名字确实标识了这个类.
另一方面,函数名称是一种组标识.您可以使用完全相同的名称在范围内定义任意数量的函数.当您使用函数名称来调用函数时,编译器必须通过查看各种可能性并使用提供的参数匹配每个函数的签名来确定您真正意味着哪个函数.共享名称的各种功能之间没有关系; 他们是完全独立的实体.
所以,没什么大不了的.你知道这一切,对吧?但现在让我们回到模板.
模板类的名称仍然是唯一的.虽然您可以定义部分特化,但您必须明确地专门化相同的模板化类.这种机制看起来像上面提到的函数名称解析算法,但存在显着差异 - 其中之一是,与函数原型不同,您不能在同一范围内使用不同类型的模板参数的两个类模板.
另一方面,模板化函数不需要定义唯一名称.模板化不会取代正常的功能过载机制.因此,当编译器试图找出函数名称的含义时,它必须考虑该函数名称的所有模板化和非模板化声明,将模板化的声明解析为一组模板参数赋值(如果可能)然后一旦它有一个可能的功能对象列表,选择具有正常重载分辨率的最佳功能对象.
这与模板化的类模板参数分辨率完全不同.它不是仅仅将提供的模板参数列表与声明的模板参数列表进行匹配,而是解析类模板的方式,而是必须采用可能匹配的每个模板化函数(例如,至少具有正确数量的参数) ; 通过将提供的参数与模板统一来推导模板参数; 然后将解析特化添加到重载集以进行进一步的重载解析.
我想也可以将部分特化解决方案添加到该过程中,但是部分特化和函数重载之间的相互作用会让我觉得可能导致伪魔法行为.在这种情况下,没有必要,因此没有这样的机制.(您可以完全专门化一个功能模板.完全专业化意味着没有模板参数可以推断,所以这不是问题.)
所以这就是独家新闻:你不能部分专门化模板化的功能,但是没有什么可以阻止你提供任意数量的具有相同名称的功能模板.所有这些都将在重载决议中被考虑,并且最好的将像往常一样获胜.
通常,这实际上足以满足您的超载需求.你应该像想象普通函数一样考虑模板化函数:想出一种基于提供的参数选择你想要的函数的方法.如果您觉得确实需要在函数调用中提供模板参数,而不是推导它们,只需将该函数设置为模板化类的(可能是静态的)成员,并将模板参数提供给类.
希望有帮助......
| 归档时间: |
|
| 查看次数: |
1378 次 |
| 最近记录: |