为什么接受数组的C ++模板不比根据GCC 5.3和Clang 4.0接受指针的数组更专业?

时间:2018-01-23 16:01:03

标签: c++ c++11 templates standards-compliance partial-ordering

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

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

II。 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

因此模板II应该更加专业化,应该在以下代码中选择:

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

为什么GCC 5.3和Clang 4.0不适用?

1 个答案:

答案 0 :(得分:1)

模板声明不含糊不清;以下代码编译并运行OK:

#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));

这样可以正常工作。