Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么可以';编译器是否从默认参数推断模板类型?_C++_Templates_Default Arguments - Fatal编程技术网

C++ 为什么可以';编译器是否从默认参数推断模板类型?

C++ 为什么可以';编译器是否从默认参数推断模板类型?,c++,templates,default-arguments,C++,Templates,Default Arguments,我很惊讶以下代码导致无法推断T错误的模板参数: struct foo { template <typename T> void bar(int a, T b = 0.0f) { } }; int main() { foo a; a.bar(5); return 0; } structfoo { 模板 空心条(内部a,T b=0.0f) { } }; int main() { 福阿; a、 酒吧(5); 返回0; } 调用a.bar(5)可以解决此问

我很惊讶以下代码导致
无法推断T
错误的模板参数:

struct foo
{
  template <typename T>
  void bar(int a, T b = 0.0f)
  {
  }
};

int main()
{
  foo a;
  a.bar(5);

  return 0;
}
structfoo
{
模板
空心条(内部a,T b=0.0f)
{
}
};
int main()
{
福阿;
a、 酒吧(5);
返回0;
}

调用
a.bar(5)
可以解决此问题。为什么编译器不能从默认参数推断类型?

在C++03中,规范明确禁止使用默认参数推断模板参数(C++03§14.8.2/17):

无法从函数默认参数的类型推断模板类型参数

在C++11中,可以为函数模板提供默认模板参数:

template <typename T = float>
void bar(int a, T b = 0.0f) { }
模板
空条(inta,tb=0.0f){}
不过,默认模板参数是必需的。如果未提供默认模板参数,则默认函数参数仍不能用于模板参数推断。具体而言,以下内容适用(C++11 14.8.2.5/5):

非推断上下文为:

  • 在函数参数的参数类型中使用的模板参数,该函数参数具有一个默认参数,该默认参数正在为其执行参数推断的调用中使用

一个很好的理由可能是

void foo(bar, xyzzy = 0);
类似于一对重载

void foo(bar b) { foo(b, 0);  }
foo(bar, xyzzy);
此外,有时将其重构为以下内容是有利的:

void foo(bar b) { /* something other than foo(b, 0); */ }
foo(bar, xyzzy);
即使编写为一个函数,它仍然像一个函数中的两个函数,从任何意义上说,这两个函数都不是“首选”函数。您正在调用单参数函数;两个参数之一实际上是一个不同的函数。默认参数表示法只是将它们合并为一个参数

如果重载具有您所要求的行为,那么为了保持一致性,它必须在模板拆分为两个定义的情况下工作。这是没有意义的,因为这样的推论就是从一个没有被调用的无关函数中提取类型!如果没有实现,这将意味着重载不同的参数列表长度与“默认参数”相比成为“二等公民”


如果客户完全不知道重载和默认值之间的区别,这是很好的。

一般来说,实现这一点会有一些技术困难。请记住,模板中的默认参数在需要时才会实例化。考虑一下:

template<typename T, typename U> void f(U p = T::g());  // (A)
template<typename T> T f(long, int = T());  // (B)
int r = f<int>(1);
template void f(U p=T::g());//(A)
模板tf(长,int=T());//(B)
int r=f(1);
今天,通过执行(除其他事项外)以下步骤解决此问题:

  • 尝试推导候选(A)和(B)的模板参数; 这对(A)不起作用,因此被消除
  • 执行过载解决;(B) 被选中
  • 形成调用,实例化默认参数

  • 为了从默认参数进行推断,在完成推断过程之前,该默认参数必须自身实例化。这可能会失败,导致SFINAE环境之外的错误。也就是说,可能完全不适合调用的候选函数可能会触发错误。

    当说“因为标准这么说”是一个有效的答案时,最好了解其背后的原因。除其他原因外,函数的不同声明可以声明不同的默认参数(我相当肯定这同样适用于函数模板。)@James:不,不同的声明不允许声明不同的默认参数。甚至不允许多个声明为同一个参数提供相同的默认值。8.3.6说“默认参数不能由以后的声明重新定义(甚至不适用于相同的值)。“当然,这只适用于非模板函数。对于模板函数,似乎只能在初始声明中提供默认参数。除了默认模板参数之外,另一种解决方法是使用第二个函数调用第一个函数,该函数使用适当的默认
    内联无效条(inta){bar(a,0.0f);}
    听起来很合理。