【发布时间】:2010-09-13 09:03:24
【问题描述】:
This question 让我思考。有时,如果无法定义参数的公共typedef,则从类模板特化中获取实际参数很有用。在 C++03 中,这是模板设计不佳或设计意图相反的标志,并不特别常见。但是可变参数模板使 typedef 覆盖变得不可能,所以如果有一个工具来解决这个问题而不需要额外的工作,那就太好了。
C++0x 解决了一个特定可变参数模板tuple 的typedef 问题。
tuple_element< 2, tuple< char, short, int > >::type my_int; // nth element type
但是tuple_element 没有和tuple 结婚;它也适用于pair 和array。它的声明没有提到tuple。
template< size_t index, typename something_like_a_tuple >
struct tuple_element; // general case is left incomplete, unimplemented
tuple 通过部分特化相关:
template< size_t index, typename ... tuple_elements >
struct tuple_element< index, tuple< tuple_elements ... > > { // impl. in here
但没必要。模板模板参数可以匹配tuple,以及仅在类型上参数化的任何其他模板。
template< size_t index,
template< typename ... > class template_over_types,
typename ... types >
struct tuple_element< index, template_over_types< types ... > > {
这将允许
tuple_element< 1, almost_any_template< char, int > >::type my_int;
tuple_element< 0, pair< int, char > >::type another_int; // same specialization
但允许array 的额外专业化
template< size_t index, typename element, size_t extent >
struct tuple_element< index, array< element, extent > >
{ typedef element type; }
不可能有冲突,因为array 的第二个参数是size_t,而不是类型。
不幸的是,用户可以为自己的类型专门化tuple_element 接口。用户的先决条件及其保证由 C++0x §17.6.3.2.1/1 给出:
只有当声明依赖于用户定义的类型并且特化满足原始模板的标准库要求并且没有明确禁止时,程序才能将任何标准库模板的模板特化添加到命名空间 std。
因此,一般特化不仅不能与array 特化冲突,而且不能与命名用户定义类型的任何 特化冲突。也就是说,如果用户声明了一个特化,通用参数 getter 的存在不会影响它是否被选中。
当实例化中出现歧义时(即,两个部分特化匹配一个参数列表),将比较备选方案以确定哪个最特化,即最不通用。调用备选方案 A 和 B。这意味着,如果 A 可以完成 B 的工作,但 B 不能完成 A 的工作,则 B 更专业。 A是通才。将选择 B。不考虑引发实例化的实际参数,因为已知它们与两个候选者都匹配。
由于我们希望通用模板遵循其他所有内容,因此我们处于良好状态。
通过用唯一的虚拟类型替换 A 中的部分特化参数来检查通用性,并检查 B 是否也可以实现这样的特化。对调角色重复,如果得到相反的结果,则认为一名候选人更专业。
用户特化中用户定义类型的存在保证了它的优先级,因为argument-getter中必须有一个与之不匹配的唯一虚拟类型。
例如,这是一个非常通用的用户声明的专业化。它为包含给定user_type 的任何类型参数化模板定义tuple_element。
template< size_t I,
template< typename ... > class any_template,
typename ... T, typename ... U >
struct tuple_element< I, any_template< T ..., ::user_type, U ... > >;
序列..., user_type, ...可以被一般情况处理,但用户的情况不能处理完全由人工唯一类型组成的序列,因为它不会包含user_type。
如果任何用户专业化是候选者,它将是更优秀的。
(该标准确实在伪代码中为tuple指定了一个单独的部分特化,但在as-if规则下可以省略它。无论如何,如果实施,它将被与protects相同的优先规则覆盖用户。)
我没有对部分排序规则进行很多尝试。这个分析正确吗?实现可以通过std::tuple_element暴露通用模板索引器吗?
【问题讨论】:
-
所以您的问题或多或少是,考虑到
tuple_element的要求,库实现者是否可以像您一样提供通用的模板参数解包器,并且不会破坏任何有效的用户专业化...? -
@Doug:差不多,是的 :v)。
标签: c++ templates c++11 standard-library partial-specialization