当参数是函数参数包

时间:2015-09-03 11:09:56

标签: c++ templates c++11 variadic-templates overload-resolution

  

N4527 14.8.2.4 [temp.deduct.partial]

     

3用于确定排序的类型取决于完成部分排序的上下文:

     

(3.1) - 在函数调用的上下文中,使用的类型是函数调用具有参数的函数参数类型。

     

(3.2) - 在调用转换函数的上下文中,使用转换函数模板的返回类型。

     

(3.3) - 在其他上下文(14.5.6.2)中使用了函数模板的函数类型。

     

4从参数模板中提取的每种类型以及参数中的相应类型   模板用作PA的类型。

     

8如果A从函数参数包转换而P不是参数包,则类型推导失败。   否则,使用结果类型PA,然后按照14.8.2.5中的描述进行推导。如果P   是一个函数参数包,参数模板的每个剩余参数类型的类型A是   与函数参数包的declarator-id的类型P进行比较。每个比较推断   由函数扩展的模板参数包中后续位置的模板参数   参数包。如果给定类型的推导成功,则考虑参数模板中的类型   至少与参数模板中的类型一样专业。   [例如:

template<class... Args>           void f(Args... args);        // #1
template<class T1, class... Args> void f(T1 a1, Args... args); // #2
template<class T1, class T2>      void f(T1 a1, T2 a2);        // #3

f();        // calls #1
f(1, 2, 3); // calls #2
f(1, 2);    // calls #3; non-variadic template #3 is more
            // specialized than the variadic templates #1 and #2

为什么f(1, 2, 3);会调用#2?

我需要更多详情,包括:

1它是哪个背景?

2什么是转化的?从#1转换而来的是void (U)void (U...)或其他形式?(U表示唯一类型)

  

14.5.6.2 [temp.func.order] / p3

     

为每种类型,非类型或模板模板参数生成转换后的模板(包括   模板参数包(14.5.3)分别合成唯一的类型,值或类模板   并将其替换为模板函数类型中每次出现的参数。

3扣除中使用的PA有哪些类型?例如

template <class T> void f(T);
int a = 1;
f(a);//P = T, A = int

1 个答案:

答案 0 :(得分:4)

  

为什么f(1, 2, 3);会调用#2?

你的问题中有很多问题(请问每个问题一个问题!),所以我会坚持这个问题。首先,我们执行模板推导。 #3失败,但#1和#2成功:

template<class... Args>
void f(Args... args);        // #1, with Args = {int, int, int}
template<class T1, class... Args> 
void f(T1 a1, Args... args); // #2, with T1 = int, Args = {int, int}

这两个函数按值int取三个,因此过载分辨率下所有正常的断路器都无法解决模糊性问题。所以我们到了最后一个:

  

鉴于这些定义,如果对于所有参数F1,ICS i ,可行函数F2被定义为比另一个可行函数i更好的函数。 (F1)并不比ICS i F2)更糟糕的转换序列,然后是    - [...]
   - F1F2是函数模板特化,F1的函数模板更专业   根据14.5.6.2中描述的部分排序规则,F2的模板。

规则是:

第1步:合成类型[temp.func.order]:

  

为每种类型,非类型或模板模板参数生成转换后的模板(包括   模板参数包(14.5.3)分别合成唯一的类型,值或类模板   并将其替换为模板函数类型中每次出现的参数。

所以我们有:

void f(Pack1... args);         // #1
void f(U2 a1, Pack2... args);  // #2

第2步:执行[temp.deduct.partial]中所述的演绎。我们所处的上下文是函数调用,因此我们使用函数调用具有参数的类型。

首先,我们尝试从#1推断#2。也就是说,我们尝试匹配(T1, Args...)与(Pack1...)。第一部分是P = T1, A = Pack1...。我们有:

  

如果A是从函数参数包转换而P不是参数包,则类型推导失败。

因此从#1中推导#2失败,因此参数Args...至少不如T1, Args...那么专业。

接下来,我们尝试从#2中推断#1。也就是说,我们尝试将(Args...)(U2, Pack2...)匹配。这很成功,因此T1, Args...至少与Args...一样专业。

由于#2至少与#1一样专业,而#1至少不像#2那样专业,我们可以说#2更专业化:

  

函数模板F至少与函数模板G一样专用,如果对于每对类型用于   确定排序,F中的类型至少与G中的类型一样专业。 F更专业   如果G至少与F一样专业,而G至少与G一样专业,则F<script> var buttons = { Join: { text: '{translate id=1434}', click: function(e) { e.preventDefault(); showLoadingScreen(); showMiniSearchLoadingScreen(); performAction({ action: "addPlayer", playerid: {$playerdetails.player_id}, starting: 1, leagueid: memberleagueid }); // close dialog after adding player $( this ).dialog( "destroy" ); } } } $( "#dialog" ).dialog({ resizable: false, width: 855, height: 650, modal: true, dialogClass: 'no-close fixed-dialog player-profile-dialog', buttons: buttons, }).attr('id', 'dialog'); function newPopup(url) { popupWindow = window.open( url,'popUpWindow','height=700,width=960,left=10,top=10,resizable=no,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no,status=yes') } $(document).ready(function() { // Get context with jQuery - using jQuery's .get() method. var ctx = document.getElementById("myChart").getContext("2d"); var data = { labels: ["January", "February", "March", "April", "May", "June", "July"], datasets: [ { label: "My First dataset", fillColor: "rgba(220,220,220,0.2)", strokeColor: "rgba(151,187,205,1)", pointColor: "rgba(151,187,205,1)", pointStrokeColor: "#fff", pointHighlightFill: "#fff", pointHighlightStroke: "rgba(220,220,220,1)", data: [65, 59, 80, 81, 56, 55, 40] } ] }; var options = { //animation: false, //scaleoverride: true, responsive: false, maintainAspectRatio: true, bezierCurve: false, animationSteps: 1, scaleShowGridLines: true, scaleShowLabels: true, pointHitDetectionRadius: 5, pointDotRadius: 3, pointDotStrokeWidth: 0, scaleFontColor: "#2b2b2b", tooltipFillColor: "rgba(255, 255, 255, 0.8)", tooltipFontColor: "#2b2b2b", tooltipFontSize: 12, multiTooltipKeyBackground: "transparent", tooltipStrokeColor: "rgba(43,43,43,0.7)", tooltipTitleFontColor: "#2b2b2b", multiTooltipTemplate: {literal}'<% if (datasetLabel) {%><%= datasetLabel %>: <%= value %> <%if ( optional.ranking ) {%> - {/literal}{translate id=480}{literal}: <%= optional.ranking %> <%} }%>',{/literal} legendTemplate: {literal}"<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){ if (datasets[i].label) {%><li><span class=\"chartLegendColor\" style=\"background-color:<%=datasets[i].pointColor%>\"></span><%if(datasets[i].label){%><span class=\"chartLegendLabel\"><%=datasets[i].label%></span><%}%></li><%} }%></ul>"{/literal} }; var myLineChart = new Chart(ctx).Line(data, options); }); 更长。

首选更专业的模板,因此我们称之为#2。