包含模板参数包的函数模板的部分排序 [英] Partial ordering of function templates containing template parameter packs

查看:165
本文介绍了包含模板参数包的函数模板的部分排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


包含模板参数包的函数模板的部分排序与这些模板参数包的推导参数数量无关。

Partial ordering of function templates containing template parameter packs is independent of the number of deduced arguments for those template parameter packs.



template<class...> struct Tuple { };
template<          class... Types> void g(Tuple<Types ...>);        // #1
template<class T1, class... Types> void g(Tuple<T1, Types ...>);    // #2
template<class T1, class... Types> void g(Tuple<T1, Types& ...>);   // #3

g(Tuple<>());                     // calls #1
g(Tuple<int, float>());           // calls #2
g(Tuple<int, float&>());          // calls #3
g(Tuple<int>());                  // calls #3

上面引用的是部分排序重载函数模板。我不太明白为什么 g(Tuple< int>()); // calls#3 。具体来说,为什么不能调用#2 ?以下是我的推理,请指出任何错误:

The above is quoted from partial ordering of overload function templates. I don't quite understand why g(Tuple<int>()); // calls #3. Specifically, why can't #2 be called? The following are my reasoning, please point out any mistakes :

注意:我将忽略#1 b / c 此处

Note: I will ignore #1 b/c it is explained well here

第1步:扣除和替换以及重载解决方案提供以下内容:

Step 1: Deduction and substitution and overload resolution come up with these:


  • void(Tuple& )[T1 = int,Types is empty]#2

  • void(Tuple )[T1 = int,Types& is empty]#3

步骤2 :转换两个函数模板:

Step 2: Transform both function templates:


  • void g(Tuple );

  • void g(Tuple );

Step3 :这是一个函数调用上下文,类型是这些函数参数函数调用具有参数的类型:

Step3: This is a function call context, the types are those function parameter types for which the function call has arguments:


  • Deduce Tuple< T1,Types ...> from Tuple& C2,Pack& ...> OK [T1 = C2; Types ... = Pack& ...]

  • Deduce Tuple< T1,Types& ...> from Tuple< C1,Pack1 ...>)OK? [T1 = C1;怎么样的类型?它可以从Pack1推导...? ]


3)如果P是引用类型, P用于扣除。看起来很好。

如果P具有包含模板参数列表< T> I>,则该模板参数列表的每个元素Pi与其A的对应模板参数Ai匹配。如果最后一个Pi是包扩展,则将其模式与A的模板参数列表中的每个剩余参数进行比较。

If P has one of the forms that include a template parameter list < T> or < I>, then each element Pi of that template argument list is matched against the corresponding template argument Ai of its A. If the last Pi is a pack expansion, then its pattern is compared against each remaining argument in the template argument list of A. A trailing parameter pack that is not otherwise deduced, is deduced to an empty parameter pack.

步骤4 :如果最后一步是正确的。那么它意味着#3不比#2更专业。

Step4:If the last step is correct. Then it means #3 is not more specialized than #2. So it is ambiguous as to which function template should be resolved to.

更新:我想我误解了上面的相关引用。当我们将P中的模板参数与A中的模板参数进行匹配时,它们会逐字匹配,这意味着在匹配时,函数调用参数和参数上完成的所有变换和分析都不会再应用在P / A(实际上函数调用参数/参数)中的模板参数/参数。然后,它会在第3步中失败,推导出 Tuple< T1,Types& ...> 来自 Tuple< C1,Pack1 ...>)。因此#3 更专业。

Update: I think I misunderstood the relevant quotes above. When we match up template parameters in P with template arguments in A, they are matched up verbatim, which means that all the transforms and analysis done on function call parameters and arguments do not apply again when we match up template parameters/arguments in P/A(actually function call parameter/arguments). Then it will fail in Step 3 above to deduce Tuple< T1, Types&...> from Tuple< C1, Pack1...>). So #3 is more specialized.

推荐答案

重载解析的第一步是找到所有候选项。对于 g(Tuple< int>()),有三个可行的候选者:

First step in overload resolution is finding all the candidates. For the call g(Tuple<int>()), there are three viable candidates:

g(Tuple<int>); // #1: [Types = {int}]
g(Tuple<int>); // #2: [T1 = int, Types = {}]
g(Tuple<int>); // #3: [T1 = int, Types = {}]

从转换序列的角度(因为,当然,他们都采用相同的参数,是输入的完全匹配)。它们都是函数模板的特殊化,所以我们不能在这个基础上进行区分。

All three are equally viable candidates from the perspective of conversion sequences (since, of course, they all take the same argument which is an Exact Match for the input). They are all function template specializations, so we can't differentiate on that basis either.

所以我们留下函数模板的部分排序。我们为每个重载合成类型,并尝试使用我们的合成类型对每个其他重载执行模板扣除。更简单的比较是(1)vs(2)和(1)vs(3)。在那里,我们有[temp.deduct.partial]:

So we're left with function template partial ordering. We synthesize types for each of the overloads and attempt to perform template deduction with our synthesized types against each of the other overloads. The simpler comparison is (1) vs (2) and (1) vs (3). There, we have [temp.deduct.partial]:


如果A从函数参数包转换而来,而P不是参数包

If A was transformed from a function parameter pack and P is not a parameter pack, type deduction fails.

由于我们将 Types ... 转换为 UniqA ... ,第一个参数是 T1 ,类型扣除失败。这使得(2)和(3)两者比(1)更专门化。现在我们比较(2)和(3)。

Since we transform Types... into UniqA..., and the first parameter is T1, type deduction fails. That makes (2) and (3) both more specialized than (1). So now we compare (2) and (3).

首先,我们可以从(3)推导出(2)?

First, can we deduce (2) from (3)?

template <class T1, class... Types> void g(Tuple<T1, Types...> );

g(Tuple<Uniq3, Uniq3Pack&...>());

当然,没有问题 T1 == Uniq3 Types ... == Uniq3Pack& ... 。接下来,我们尝试另一个方向:

Sure, no problem T1 == Uniq3 and Types... == Uniq3Pack&.... Next, we try the other direction:

template <class T1, class... Types> void g(Tuple<T1, Types&...> );

g(Tuple<Uniq2, Uniq2Pack...>());

这会失败,因为 Uniq2Pack 一组引用类型和 Types& ... 是。由于扣除只在一个方向上成功,这使得(3)更专门的过载。

This fails, since Uniq2Pack isn't a pack of reference types and Types&... is. Since deduction only succeeds in one direction, that makes (3) the more specialized overload.

由于它是最后一个站,(3)是最可行的候选人。它可能看起来违反直觉,因为我们实际上不是用引用类型调用它 - 但它仍然是最好的选择。

As it's the last one standing, (3) is the best viable candidate. It may seem counterintuitive, since we're not actually calling it with a reference type - but it's still the best choice.

这篇关于包含模板参数包的函数模板的部分排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆