15

为什么接下来的两个模板声明模棱两可(所以没有一个比另一个更专业)?我知道这个问题已经在 Stack Overflow 上提出过很多次,但通常人们会回答如何解决歧义,而不是为什么会发生这种情况。

我。 template <class T> void func(char* buf, T size) {}

二、 template <std::size_t N> void func(char (&buf)[N], std::size_t size) {}

尝试通过 C++14 标准的步骤来解决部分函数模板排序 (14.5.6.2):

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

转换函数 I 模板的函数类型是:void func(char*, U1),其中U1是一些独特的合成类型。

转换后的函数 II 模板的函数类型是:void func(char (&buf)[N1], std::size_t),其中N1是一些独特的合成值。

使用转换后的函数模板的函数类型,对另一个模板执行类型推导,如 14.8.2.4 中所述。

因此,让我们尝试在一侧(使用第一个模板作为参数,第二个模板作为参数模板)和另一侧执行类型推导。

情况1。

参数模板:template <std::size_t N> void func(char (&buf)[N], std::size_t size). 转换后的参数模板:void func(char*, U1).

试图推断模板参数。" char (&buf)[N]" 不能从 " char*" 类型推导出来。U1 也不匹配std::size_t类型。失败的。

案例 2。

参数模板:template <class T> void func(char* buf, T size). 转换后的参数模板:void func(char (&buf)[N1], std::size_t).

试图推断模板参数。参数模板的第一个参数根本不是类型,它与char[]. T应推导出来std::size_t

所以模板二应该更专业,应该在下面的代码中选择:

char buf[16];
func(buf, static_cast<std::size_t>(16));

为什么 GCC 5.3 和 Clang 4.0 不是这样?

4

1 回答 1

1

模板声明没有歧义;以下代码编译并运行正常:

#include <iostream>
#include <string>

using namespace std;

template<class T>
void func(char* buf, T size) {cout<<"void func(char*,T)\n";}
template<size_t N>
void func(char (&buf)[N], std::size_t size) {
  cout<<"void func(char (&)[],size_t)\n";}

int main() {
  char buf[3];
  func(buf, 2);
  func<3>(buf, 2);
  func(reinterpret_cast<char (&)[3]>(buf), 2);
  //next is ambiguous
  //func(reinterpret_cast<char (&)[3]>(buf), size_t(2));
  func<3>(reinterpret_cast<char (&)[3]>(buf), size_t(2));
  return 0;
}

但是,注释掉的调用是模棱两可的。要消除歧义,请使用:

func<3>(reinterpret_cast<char (&)[3]>(buf), size_t(2));

这可以正常工作并调用正确的函数。

于 2018-04-10T16:31:00.977 回答