过载分辨率和部分模板排序 [英] Overload resolution and partial template ordering

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

问题描述

考虑这个简单的函数模板对。

 模板< typename T> 
void foo(T&){std :: cout<< __PRETTY_FUNCTION__<< '\\\
'; }

template< typename C>
void foo(const C&){std :: cout<< __PRETTY_FUNCTION__<< '\\\
'; }



如果我们调用 foo -const参数:

  int i = 4; 
foo(i);

T& [over.ics.rank] /3.2.6,因为推导出的参考 int& 少于推导的参考 $ c> const int& 。



但是,如果我们调用 foo const参数:

  const int ci = 42; 
foo(ci);

const C& 它是更专业基于[over.match.best] /1.7。但是,什么是规则来确定呢?我的理解是,你合成一个类型 C (调用它, M )并尝试执行扣除 foo(M) - 但是会成功( T == M )。这只是一个右值,导致扣除失败 - 但编译器如何知道它必须在合成步骤中选择一个右值。

解决方案

免责声明:我们考虑的类型始终是参数类型。类型/值类别/ etc。



部分排序考虑了两个turn的重载,其中一个模板总是参数模板,另一个模板是参数模板。 [temp.deduct.partial] / 2:


对于每个涉及的模板,都有原始的函数类型
和变换函数类型。 [..]扣除
过程使用转换类型作为参数模板,并将另一个模板的
原始类型用作参数模板。这个
过程对于部分排序中涉及的每个类型
进行两次:比较:一次使用转换的模板-1作为参数
模板并且使用模板-2作为参数模板,并再次使用
将模板-2转换为参数模板,将模板-1作为
参数模板。


熟悉变换后的模板的生成方式。这在§14.5.6.2/ 3中指定。


要生成转换的模板,对于每个类型,非类型或
模板模板参数(包括其中的模板参数包
(14.5.3))分别合成唯一的类型,值或类模板
,并将其替换为该参数的每次出现


所以我们的(转换的)参数模板是

  void foo(Unique1&); 

void foo(Unique2 const&);

[temp.deduct.partial] / 3& / 4:


用于确定排序的类型取决于
中的上下文, p>



  • 函数调用的上下文中,所使用的类型是
    的函数参数类型,参数。 [..]



上面从参数模板中提名的每个类型和参数
模板中的相应类型都用作 P A 的类型。


因此我们有两个回合,在两个回合中,我们有一个类型 P 和类型 A



转1:

     P1 :  ;  T const&

     A1 :   Unique1&



转2:

     P2 :   T&

     A2 :  Unique2 const&



但在乐趣开始之前,对这些类型进行一些转换 - temp.deduct.partial] / 5& / 7:




  • 如果 P code>是引用,那么它们将被它们引用的类型替换。




请注意,删除的cv-限定符被记住以供稍后使用。 [temp.deduct.partial] / 6:


如果 P code> A 是引用类型(在被上面引用的
类型替换之前),确定两种类型(如果有)中的哪一个是
more cv-合格的;否则类型被认为是
同样cv限定为部分排序目的。以下将使用此确定的结果


因此,我们留下



转1:

     P1 :  T

     A1 :   Unique1



转2:

     P2 :   T

     A2 :  Unique2



现在我们执行扣除 - 通过设置 T = Unique [1/2] 。从[temp.deduct.partial] / 8:


如果扣除对于给定类型成功,则参数模板中的类型被认为是
至少与参数模板中的类型一样专用。


这给了我们 Unique1& 至少与 T const& 一样专业,并且 Unique2 const& 至少与 T& 一样专业。






,这是[temp.deduct.partial] /(9.2)步骤:


如果对于给定类型,扣除成功两个方向(即,
类型在上述变换之后是相同的)以及 P
A 是引用类型(在被替换为引用
的类型之前):




  • ];否则,


  • 如果参数模板的类型比参数模板
    的类型),参数类型至少与参数
    类型一样专用。





记住的cv限定符发挥作用。 A2 是比 P2 更多的cv限定(如上所述) P2 不被视为至少与 A2 同样专业。



最后,[temp.deduct.partial] / 10:


函数模板 F 至少与函数模板 G
一样专门,如果对于用于确定排序的每对类型,来自 F 的类型
至少与来自 G 的类型相同。

F 更专业化
G 如果 F 至少与 G G 一样专业,至少不如 F

意味着由于 T& <<>没有至少与 Unique2 const& 一样专门,我们已经确定 T const& 至少与 Unique1& 一样专业, T const& T& -overload。






目前属于 CWG#2088 由R Smith创建的四个月前:


对于lvalue-vs-rvalue引用的迟到的破产者和
cv- 14.8.2.4 [temp.deduct.partial]第9段是
应用


如果对于给定类型,扣除成功两个方向(即,
类型在上述变换之后是相同的),并且 P A
是引用类型(在用以上引用
的类型替换之前):


假设假设。 [...]我们需要决定规则是扣除在双向上成功还是类型相同。后者似乎更为合理。


这不会改变建立的结果,因为我们得到的类型确实相同。


Consider this simple pair of function templates.

template <typename T>
void foo(T& ) { std::cout << __PRETTY_FUNCTION__ << '\n'; }

template <typename C>
void foo(const C& ) { std::cout << __PRETTY_FUNCTION__ << '\n'; }

If we call foo with a non-const argument:

int i = 4;
foo(i);

The T& overload is preferred based on [over.ics.rank]/3.2.6, since the deduced reference int& is less cv-qualified than the deduced reference const int&.

However, if we call foo with a const argument:

const int ci = 42;
foo(ci);

The const C& overload is preferred because it is "more specialized" based on [over.match.best]/1.7. But what are the rules to determine this? My understanding was that you synthesize a type for C (call it, M) and try to perform deduction on foo(M) - but that would succeed (with T == M). It's only an rvalue that would cause that deduction to fail - but how does the compiler know that it has to choose an rvalue in the synthesis step?

解决方案

Disclaimer: The types we consider are always types of parameters. The types/value categories/etc. of the actual arguments passed are solely considered in overload resolution, never in partial ordering.

Partial ordering considers both overloads in two "turns", in which one template is always the parameter template, and the other template is the argument template. [temp.deduct.partial]/2:

For each of the templates involved there is the original function type and the transformed function type. [..] The deduction process uses the transformed type as the argument template and the original type of the other template as the parameter template. This process is done twice for each type involved in the partial ordering comparison: once using the transformed template-1 as the argument template and template-2 as the parameter template and again using the transformed template-2 as the argument template and template-1 as the parameter template.

You should be familiar with the way transformed "templates" are generated. This is specified in §14.5.6.2/3.

To produce the transformed template, for each type, non-type, or template template parameter (including template parameter packs (14.5.3) thereof) synthesize a unique type, value, or class template respectively and substitute it for each occurrence of that parameter in the function type of the template.

So our (transformed) argument templates are

void foo( Unique1& );

void foo( Unique2 const& );

[temp.deduct.partial]/3 & /4:

The types used to determine the ordering depend on the context in which the partial ordering is done:

  • In the context of a function call, the types used are those function parameter types for which the function call has arguments. [..]

Each type nominated above from the parameter template and the corresponding type from the argument template are used as the types of P and A.

Thus we have two turns, and in both we have a type P and a type A:

Turn 1:
    P1:   T const&
    A1:   Unique1&

Turn 2:
    P2:   T&
    A2:   Unique2 const&

But before the fun begins, some transformations are performed on these types as well - I abbreviated [temp.deduct.partial]/5 & /7:

  • If P or A are references, then they're replaced by the type they refer to.
  • Any top-level cv-qualifiers are removed.

Note that the removed cv-qualifiers are "remembered" for later. [temp.deduct.partial]/6:

If both P and A were reference types (before being replaced with the type referred to above), determine which of the two types (if any) is more cv-qualified than the other; otherwise the types are considered to be equally cv-qualified for partial ordering purposes. The result of this determination will be used below.

Thus we're left with

Turn 1:
    P1:   T
    A1:   Unique1

Turn 2:
    P2:   T
    A2:   Unique2

Now we perform deduction - which clearly succeeds in both turns by setting T=Unique[1/2]. From [temp.deduct.partial]/8:

If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template.

That gives us both that Unique1& is at least as specialized as T const&, and that Unique2 const& is at least as specialized as T&.


However, this is where [temp.deduct.partial]/(9.2) steps in:

If, for a given type, deduction succeeds in both directions (i.e., the types are identical after the transformations above) and both P and A were reference types (before being replaced with the type referred to above):

  • [..]; otherwise,

  • if the type from the argument template is more cv-qualified than the type from the parameter template (as described above), the parameter type is not considered to be at least as specialized as the argument type.

The remembered cv-qualifiers come into play. A2 is "more cv-qualified (as described above)" than P2, hence P2 is not considered to be at least as specialized as A2.

Finally, [temp.deduct.partial]/10:

Function template F is at least as specialized as function template G if, for each pair of types used to determine the ordering, the type from F is at least as specialized as the type from G.
F is more specialized than G if F is at least as specialized as G and G is not at least as specialized as F.

implies that since the type T& is not at least as specialized as Unique2 const& and we already established that T const& is at least as specialized as Unique1&, the T const&-overload is more specialized than the T&-overload.


The aforementioned rule in paragraph 9 is currently subject of CWG #2088 created four months ago by R. Smith:

The late tiebreakers for lvalue-vs-rvalue references and cv-qualification in 14.8.2.4 [temp.deduct.partial] paragraph 9 are applied

If, for a given type, deduction succeeds in both directions (i.e., the types are identical after the transformations above) and both P and A were reference types (before being replaced with the type referred to above):

However, this is based on a false assumption. [..] We need to decide whether the rule is "deduction succeeds in both directions" or "the types are identical." The latter seems more reasonable.

This will not alter the result established though, since the types we got are indeed identical.

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

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