可以将std :: tuple_element double作为通用模板参数检索器吗?

时间:2010-09-13 09:03:24

标签: c++ templates c++11 standard-library partial-specialization

This question让我思考。有时,如果未能定义参数的公共typedef,则从类模板特化中获取实际参数是有用的。在C ++ 03中,它表示模板设计不良或设计意图相反,并不常见。但是可变参数模板使得typedef覆盖变得不可能,所以如果没有额外的工作就可以使用一个工具来解决问题。

C ++ 0x解决了一个特定可变参数模板typedef的{​​{1}}问题。

tuple

tuple_element< 2, tuple< char, short, int > >::type my_int; // nth element type 未与tuple_element结婚;它也适用于tuplepair。它的声明没有提及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接口专门用于他们自己的类型。用户的前提条件及其保证由C ++0x§17.6.3.2.1/ 1:

给出
  

只有当声明取决于用户定义的类型并且特化符合原始模板的标准库要求且未明确禁止时,程序才可以将任何标准库模板的模板特化添加到命名空间std。

因此,一般专业化不仅不能与tuple_element专业化冲突,也不能与命名用户定义类型的任何专业化冲突。也就是说,如果用户声明了一个特化,那么一般参数getter的存在不会影响它是否被选中。

当在实例化中出现歧义时(即,两个部分特化与参数列表匹配),比较替代方案以确定哪个是最专业的,换句话说是最不一般化的。调用备选方案A和B.这意味着,如果A可以做B的工作,但B不能做A的工作,那么B更专业。 A是通才。 B将被选中。不考虑启动实例化的实际论点,因为已知它们与两个候选者都匹配。

由于我们希望通用模板遵循其他所有内容,因此我们处于良好状态。

通过将A中的部分特化参数替换为唯一的虚拟类型来检查通用性,并检查B是否也可以实现这样的特化。重复角色颠倒,如果获得相反的结果,则知道一个候选人更专业。

在用户的特化中存在用户定义的类型保证了它的优先级,因为在argument-getter中必须有一个与之不匹配的对应的唯一虚拟类型。

例如,这是一个非常通用的用户声明的专业化。它为包含给定array的任何类型参数化模板定义tuple_element

user_type

序列 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指定了一个单独的部分特化,但它可以在as-if规则下省略。无论如何,如果实现,它将被相同的优先规则覆盖保护用户。)


我没有对部分订购规则进行过多次尝试。这个分析是否正确?实现是否可以通过tuple公开通用模板索引器?

1 个答案:

答案 0 :(得分:1)

  

因此,不仅通用专业化不必与数组专用化冲突,它也不能与任何命名用户定义类型的专业化冲突。也就是说,如果用户声明了一个特化,那么一般参数getter的存在不会影响它是否被选中。

我不明白这一点。你的意思是什么?


  

实现是否可以通过std :: tuple_element公开通用模板索引器?

对于一般情况,这是不可能的。想象一下这个

template<int A, char B, long C, class D, int &X, int(*Handler)()>
struct funny_template { };

int x, y();
std::tuple_element<3, funny_template<1, 2, 3, long, x, y> >::type along = 0;

快乐的宏元编程:)


  

我没有对部分订购规则进行过多次尝试。这种分析是否正确?

两个部分特化的部分排序

template<class A1, ..., class AN>
class T<Am1, ..., AmM>;

template<class B1, ..., class BL>
class T<Bm1, ..., BmM>;

就像将它们转换为功能模板并订购它们

一样
template<class A1, ..., class AN>
void f(T1<Am1, ..., AmM>);

template<class B1, ..., class BL>
void f(T2<Bm1, ..., BmM>);

正如您的分析所说的部分排序正确地为每个模板参数添加唯一类型,将其转换为参数推导的参数,并将其与其他模板进行比较

T1A<Uam1, ..., UAmM> -> T2<Bm1, ..., BmM>
T2A<UBm1, ..., UBmM> -> T1<Am1, ..., AmM>

如果存在未推断的上下文,则不会像平时那样进行比较。就像BmMtypename Foo::X一样,上面的第一个推论会考虑将最后一个子类型推断为成功,因为非受限上下文不会存在不匹配。但另一方面,Foo::XAmM 可能不匹配,但AmM不是非受限上下文本身。

如果扣除成功一轮而不是相反(...因为它们只发生在实际的功能模板排序中而忽略了一些其他规则),上面右侧的模板对于未能扣除的轮次更多专门。否则,部分特化是无序的。