当前位置: 首页 > 知识库问答 >
问题:

当参数为函数参数包时,在偏序期间推断模板参数

武琛
2023-03-14

N4527 14.8.2.4[温度扣除部分]

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

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

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

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

4以上从参数模板中指定的每种类型以及从参数模板中指定的相应类型都用作P和A的类型。

8如果A是从函数参数包转换而来的,并且P不是参数包,则类型推导失败。否则,使用生成的类型PA,然后按照14.8.2.5中所述进行推导。如果P是函数参数包,则将参数模板的每个剩余参数类型的类型A与函数参数包的声明符-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什么是转化的From
例如#1的转换自为void(U),void(U…) 或其他形式?(U表示唯一类型)

14.5.6.2[温度功能订单]/p3

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

3在扣除中使用的PA类型是什么?例如

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

共有1个答案

汪博艺
2023-03-14

为什么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被定义为比另一个可行函数F2更好的函数,如果对于所有参数i,ICS i不是比ICS i更差的转换序列,那么 F1和 F2是函数模板的专门化,根据14.5.6.2中描述的偏序规则,F1的函数模板比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 至少与参数一样专业化

由于#2至少与#1一样专业,而#1至少没有#2那么专业,我们可以说#2更专业:

如果对于用于确定顺序的每对类型,F中的类型至少与G中的类型一样专用,则F中的功能模板至少与G中的功能模板一样专用<如果F至少与G一样专业,而G至少与F一样专业,则F比G更专业。

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

 类似资料:
  • 已编辑(原始问题只有int A,int B): 模板参数推断在两个专门化之间比较的#参数相同时按预期工作,但在它们不同时失败(因为在其中一个专门化中包含默认参数)。 例如:为什么模板参数推导在一种情况下与另一种情况下失败,有人能指出解释这一点的任何资源/标准吗? 错误:模糊模板实例化'类Foo

  • 如果我没有理解错的话,类模板定义了一个函数,所以当我调用时,编译器有可能进行隐式强制转换,但是在函数模板的情况下,此时没有函数定义,所以隐式强制转换不会发生。 但我不明白为什么编译器不能创建函数定义,然后应用隐式强制转换? 错误是: 在函数“int main()”中:    25:24:错误:调用“test2::add(void(&)(int))”没有匹配函数    25:24:注:候选人是:  

  • 这是在参数是重载函数时重载解析如何工作中提到的更复杂的问题? 下面的代码编译起来没有任何问题: 模板参数推导似乎不是一项具有挑战性的任务-只有一个函数接受两个参数。但是,取消注释的模板重载(仍然只有一个参数)会无缘无故地破坏编译。gcc 5. x/6. x和clang 3.9的编译都失败了。 它可以用重载解析/模板参数推导规则来解释,还是应该在这些编译器中被限定为缺陷?

  • 受这个答案的启发,我生成了这段代码,其输出取决于编译器: 如果使用 GCC 11 编译,调用

  • 我目前有一个,但是为了灵活性,我希望能够分配一个lambda表达式,将作为映射中的值返回。 所以我创建了这个模板类: 并像这样使用它: IntelliSense提供了更多信息: 多个操作符“=”匹配这些操作数:function“valueorfunction::operator=(const std::function&other)[with T=std::wstring]”function“va

  • 假设有一个模板函数 接受任意数量的参数。给定最后一个参数始终是 ,我如何实现下面显示的 模板,以便 包含此 的参数? 例如,如果像这样调用,应该是: 我的第一个想法是: 但这不会编译: 问题一: 为什么这不能编译?为什么模板参数演绎失败? 最终,我想出了这个解决方案: 这里,是,即中的最后一种类型。然后,的临时值被传递到,其中。这行得通,但在我看来很难看。 问题二: 我想知道如果没有两个函数和的临