【问题标题】:Surprise in template parameter substitution?模板参数替换的惊喜?
【发布时间】:2017-05-15 13:12:25
【问题描述】:

N3690,第 14.8.2 节第 3 段有这个令人兴奋的例子:

template <class Z> void h(Z, Z*);
// #5: function type is h(int, const int*)
h<const int>(1,0);

问题:为什么不是h(const int, const int*)

据了解,Z = const int,所以模板声明中每次出现的Z 都可以读作const int,还是我遗漏了什么?为什么指针不一样?我记得当参数有T&amp;T* 时,它会保留T 的cv-qualifiers,但我看不出有任何可能在这里应用它。

【问题讨论】:

  • 我不认为函数签名有 const 参数这样的东西。任何未通过引用传递的参数都将被复制;提供的参数的constness 在那里无关紧要。 const 只适用于定义,是一个实现细节。

标签: c++ templates c++14 language-lawyer


【解决方案1】:

您需要查看 [dcl.fct]/5 原因:

一个名称可用于单个范围内的多个不同功能;这是函数重载(第 13 条)。函数的所有声明都应在返回类型和参数类型列表中完全一致。使用以下规则确定函数的类型。每个参数的类型(包括函数参数包)由其自己的 decl-specifier-seq 和声明符确定。在确定每个参数的类型后,将“T的数组”或“返回T的函数”类型的任何参数分别调整为“指向T的指针”或“返回T的函数的指针”。 生成参数类型列表后,任何修改参数类型的顶级 cv 限定符都会在形成函数类型时被删除。转换后的参数类型的结果列表以及省略号或函数参数包的存在与否是函数的参数类型列表。 [ 注意:此转换不影响参数的类型。例如,int()(const int p, decltype(p)) 和 int()(int, const int) 是相同的类型。 ——尾注]

const type*the const is not a top level const qualifier

【讨论】:

  • 这与@StoryTeller 的回答不一样吗?内容看起来一样,但段落编号不同。
  • @Incomputable 看起来我们都发布了相同的答案。我发这个的时候没有看到他们的(页面没有刷新)。
  • @Incomputable - 这是因为 Nathan 引用了已发布的标准,而我引用了未来的标准草案。段落移动了一些时间。
  • 请使用 [dcl.fct]。章节编号一直在变化,但章节标题往往不会。例如,在最新的草案中,现在是 11.3.5。
  • @T.C. N3797,这是我的一个错字。我复制了第 5 段,但 4 在我的屏幕顶部,所以当我寻找数字时,我看到了 4 并使用了它。答案已更新。
【解决方案2】:

原因是另一个标准段落:

[dcl.fct/5]

一个名称可以在一个单一名称中用于多个不同的功能 范围;这是函数重载。函数的所有声明 应在返回类型和返回值中完全一致 参数类型列表。函数的类型由使用 遵循规则。每个参数的类型(包括函数 参数包)由它自己的 decl-specifier-seq 和 声明者。在确定每个参数的类型后,任何 类型为“T 数组”或函数类型 T 的参数被调整为 “指向 T 的指针”。生成参数类型列表后,any 修改参数类型的顶级 cv 限定符在以下情况下被删除 形成函数类型。 转换后的结果列表 参数类型以及是否存在省略号或 函数参数包是函数的参数类型列表。 [ 笔记: 此转换不影响参数的类型。为了 例如,int()(const int p, decltype(p)) 和 int()(int, const int) 是相同的类型。 — 尾注 ]

这样做的合理性是,对于调用者来说,如果参数是 cv 限定的,则没有区别;调用函数的步骤以及重载解析的转换顺序是相同的。所以保留 const 实际上会导致歧义。

cv-qualifier实际上是函数的一个实现细节,只在函数定义的地方有意义(你不能在函数体内修改参数)。

【讨论】:

    【解决方案3】:

    因为一般来说你需要remove cv-qualifiers 来自基本的非 POD 类型。

    C++11 中来自 § 8.3.5 Functions(第 181 页):

    5

    一个名称可用于一个程序中的多个不同功能 单一范围;这是函数重载(第 13 条)。全部 函数的声明应在两个返回中完全一致 类型和参数类型列表。确定函数的类型 使用以下规则。每个参数的类型(包括 函数参数包)由其自身确定 decl-specifier-seq 和声明符。确定每个类型后 参数,“T 数组”或“函数返回”类型的任何参数 T”调整为“指向T的指针”或“指向函数返回的指针” T,”分别。在生成参数类型列表后,任何 修改参数类型的顶级 cv 限定符在以下情况下被删除 形成函数类型。转换参数的结果列表 类型以及省略号或函数的存在与否 参数包是函数的参数类型列表。 [注:这 转换不影响参数的类型。为了 例如,int()(const int p, decltype(p)) 和 int()(int, const int) 是相同的类型。 ——尾注]

    有一个 similar question for cv-qualifiers 具有基本的非 POD 类型。

    【讨论】:

      猜你喜欢
      • 2019-07-31
      • 2017-07-22
      • 2011-10-18
      • 1970-01-01
      • 2011-09-12
      • 1970-01-01
      • 2020-02-12
      • 2013-06-20
      • 2021-04-11
      相关资源
      最近更新 更多