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

何时提供默认参数作为模板参数

郤飞英
2023-03-14
template<typename T, typename U = T>
struct Test{};
template<typename T>
void func(Test<T>){  //#1
}
int main(){
  func(Test<int>{});  //#2
}

标准中似乎没有规则提到模板参数需要默认参数的情况。

在dcl中。fct。默认值#1

如果在参数声明中指定了初始化子句,则将此初始化子句用作默认参数。缺省参数将用于缺少尾随参数的调用。

在本节中,规则明确描述了何时为函数调用提供默认参数。但是,我在标准中没有找到与上面描述何时提供默认参数作为模板参数的语句类似的引用。

例如测试

以下规则中唯一将默认参数作为模板参数引用:
temp#arg-8

当简单模板id没有命名函数时,默认模板参数将在需要该默认参数的值时隐式实例化。[ 示例:
模板

考虑代码< <代码> 1 > /代码>,缺省参数需要在<代码> 1×<代码>吗?如果是(在这一点上它似乎需要,因为如果我没有为模板参数U指定默认参数,那么在点#1将发生错误。请参见godbolt output),根据上面的引文,默认模板参数需要隐式实例化,但是在这一点上,T是一个模板参数,此类函数模板的定义没有实例化任何内容(此时它只是一个函数模板定义)。那么,这段引文是如何解释的呢?


共有2个答案

袁智明
2023-03-14

根据上面的引文,默认模板参数需要隐式实例化,但是在这一点上,T是一个模板参数,此类函数模板的定义没有实例化任何内容(这一点上只是一个函数模板定义)。那么,这段引文是如何解释的呢?

关键是实例化需要和引用时的区别。在[temp.arg]/8的示例中,U的默认模板参数被实例化,因为它是S实例化所必需的

从[临时扣减]/1[强调矿山]:

引用函数模板专用化时,所有模板参数都应具有值。这些值可以显式指定,或者在某些情况下,可以从使用中推导出来,或者从默认模板参数中获得。[...]

对于OP的特定示例,前一个(实例化)仅在重载解析完成且最佳可行重载已实例化(这反过来实例化了类模板函数参数)后发生。然而,后者(引用的函数/类模板专门化)也适用于重载解析期间,即使丢弃不可行或不是最佳可行匹配的候选项,也适用于永远不会导致实例化的候选项。

源自[temp.deduct]/2[强调我的]:

指定显式模板参数列表时,模板参数必须与模板参数列表兼容,并且必须产生如下所述的有效函数类型;否则类型扣除失败。具体而言,在针对给定函数模板计算显式指定的模板参数列表时,将执行以下步骤:

  • (2.1)指定的模板参数必须与模板参数的类型(即类型、非类型、模板)相匹配。参数不能多于参数,除非[...]

从[临时扣减]/6[强调我的]:

在模板参数推导过程中的某些点上,有必要采用使用模板参数的函数类型,并用相应的模板参数替换这些模板参数。当任何显式指定的模板参数被替换到函数类型时,在模板参数推导开始时执行此操作,当从默认参数推导或获得的任何模板参数被替换时,再次在模板参数推导结束时执行此操作。

很明显,作为“模板参数结束推导”的一部分,任何未明确指定的模板参数都将从默认参数中推导或获取,并替换到候选函数中,然后将其作为可行重载丢弃或排序。这与实例化没有任何关系,并且仅在作为重载解析的一部分引用的给定专门化(可能尚未实例化或从未实例化)的上下文中适用。

最后,从[temp.Decrete.type]/3[emphasis mine]:

给定类型P可以由许多其他类型、模板和非类型值组成:

  • [……]

我们注意到,作为函数模板参数的函数模板参数推导的一部分,函数模板参数类型(用于针对参数的推导)包括模板参数的模板参数列表引用的类型,这意味着引用了特定的类模板特殊化(函数模板参数),这样,根据[temp.deduct]/1,它将通过模板参数推导和默认参数检查任何没有显式指定的模板参数。

胡国兴
2023-03-14

[临时名称]中也有这一段:

模板ID是有效的,如果

  • 每个不可推断的非包参数都有一个参数,它没有默认的模板参数,

因此,可以考虑缺省参数意味着需要一个默认参数,以使模板ID有效,并且当缺少模板参数时,该参数是默认参数值。但是我在类模板的标准中没有发现任何明确的内容。对于函数模板,这更为明确。可能没有人指出标准中的这个漏洞,因为这是一种常见的模式:使用默认值代替用户未提供的内容。可能不会更改,因为英语词典中已经给出了默认值的定义:

信息技术如果你不做任何不同的选择,某些事情将自动发生或出现的方式,特别是在计算机上——cambrige online dictionary

 类似资料:
  • 如果允许我执行以下操作: 为什么我主要不被允许做以下事情? 但我必须具体说明以下几点: C11引入了默认的模板参数,现在我完全无法理解它们。

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

  • 是否允许在友元声明中为模板参数提供默认值? Visual Studio 2015似乎允许这样做。gcc拒绝了。我在cppreference页面上找不到任何内容。

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

  • 我有一个程序如下。有一个基本模板,以及SFINAE的部分专业化。 在2运行程序时,将打印 中的

  • 问题内容: 当我运行它时,它拒绝“ def a(…”,并用红色突出显示“(”。我不知道为什么。 问题答案: 让我在这里澄清两点: 首先,非默认参数不应跟随默认参数,这意味着您无法在函数中定义。在函数中定义参数的正确顺序为: 位置参数或非默认参数,即 关键字参数或默认参数,即 仅关键字参数,即 var-keyword参数,即 是位置参数 是可选参数 是关键字参数 是列表参数 仅限关键字 是var-k