C++ 在std::exchange中,为什么第二个模板参数是默认的?
C++14标准为C++ 在std::exchange中,为什么第二个模板参数是默认的?,c++,templates,stl,c++14,default-arguments,C++,Templates,Stl,C++14,Default Arguments,C++14标准为std::exchange指定了以下声明: template <class T, class U = T> T std::exchange(T& obj, U&& new_value); 该函数可以作为参数传递给其他函数或例如算法。在这种情况下,如果函数的两个参数具有相同的类型,那么只指定第一个模板参数就足够了 这使得代码更简短,可读性更强 这是一个人工的例子。:) 或者,该示例可以包括转换 #include <iostream>
std::exchange
指定了以下声明:
template <class T, class U = T>
T std::exchange(T& obj, U&& new_value);
该函数可以作为参数传递给其他函数或例如算法。在这种情况下,如果函数的两个参数具有相同的类型,那么只指定第一个模板参数就足够了 这使得代码更简短,可读性更强 这是一个人工的例子。:) 或者,该示例可以包括转换
#include <iostream>
#include <numeric>
#include <iterator>
#include <functional>
int main()
{
int a[] = { 1, 2, 3 };
double b[] = { 4.4, 5.5, 6.6 };
std::cout << "a: ";
for ( int x : a ) std::cout << x << ' ';
std::cout << std::endl;
std::cout << "b: ";
for ( double x : b ) std::cout << x << ' ';
std::cout << std::endl;
auto sum = std::inner_product( std::begin( a ), std::end( a ),
std::make_move_iterator( std::begin( b ) ), 0,
std::plus<>(), std::exchange<int> );
std::cout << "sum = " << sum << std::endl;
std::cout << "a: ";
for ( int x : a ) std::cout << x << ' ';
std::cout << std::endl;
}
#包括
#包括
#包括
#包括
int main()
{
int a[]={1,2,3};
双b[]={4.4,5.5,6.6};
std::coutstd::exchange
是在中提出的,没有默认的模板参数,后来又有了默认的模板参数。请注意,N3608中提供了以下推理:
给第二个模板参数一个默认值可以修复
以下两种情况:
DefaultConstructible x = ...;
if (exchange(x, {})) { ... }
int (*fp)(int);
int f(int);
double f(double);
/*...*/ exchange(fp, &f) /*...*/
第一个示例的有用性当然是,一个非类型化的临时{}
将被推断为T
。第二个示例更为复杂:
14.8.2模板参数扣除[临时扣除]
5生成的替换和调整的函数类型用作
用于模板参数推断的函数模板的类型。如果
尚未推导模板参数及其对应的模板
参数具有默认参数,则模板参数已确定
通过替换为前面的
将模板参数转换为默认参数。如果替换
导致无效类型,如上所述,类型推断失败
14.8.2.5从类型[temp.deletry.type]推断模板参数
4在大多数情况下,类型、模板和非类型值
用于组合P参与模板参数推导,即,
它们可用于确定模板参数的值,以及
这样确定的值必须与确定的值一致
但是,在某些上下文中,该值并不
参与类型推断,但使用模板的值
在别处推导或明确指定的参数。
如果模板参数仅在非推断上下文中使用,并且
未明确指定,模板参数推断失败。
5非推断上下文为:
(5.5)-不能对其进行参数推导的函数参数
完成,因为关联的函数参数是函数或集合
重载函数的一个或多个(13.4),以及以下一个或多个
适用于:
(5.5.1)-多个函数与函数参数匹配
类型(导致推断不明确)
在第二个示例中,模板参数U
仅在未推导的上下文中使用,因为两个重载f(int)
和f(double)
都可以与U
匹配。因此,不进行参数推导,U
成为T
的默认值(int(*)(int)
在这种情况下,因此选择了f(int)
)
此外,正如@vladfrommosco所解释的,在传递
std::exchange
(例如,传递到标准算法)时,使用默认参数可以缩短代码.Gah!我的心都碎了。这合法吗?看起来f
定义了两次。@JonathanMee声明了f
的两个重载。@JonathanMee,基本函数重载!?所以,fp
现在是int(*)(int)
实际上引用了double(*)(double)
?这至少会发出警告吗?还是exchange
只允许发出警告?@JonathanMee,不,它指向一个int(int)
函数。f
的第一个重载。。。。
a: 1 2 3
b: 4 5 6
sum = 6
a: 4 5 6
#include <iostream>
#include <numeric>
#include <iterator>
#include <functional>
int main()
{
int a[] = { 1, 2, 3 };
double b[] = { 4.4, 5.5, 6.6 };
std::cout << "a: ";
for ( int x : a ) std::cout << x << ' ';
std::cout << std::endl;
std::cout << "b: ";
for ( double x : b ) std::cout << x << ' ';
std::cout << std::endl;
auto sum = std::inner_product( std::begin( a ), std::end( a ),
std::make_move_iterator( std::begin( b ) ), 0,
std::plus<>(), std::exchange<int> );
std::cout << "sum = " << sum << std::endl;
std::cout << "a: ";
for ( int x : a ) std::cout << x << ' ';
std::cout << std::endl;
}
DefaultConstructible x = ...;
if (exchange(x, {})) { ... }
int (*fp)(int);
int f(int);
double f(double);
/*...*/ exchange(fp, &f) /*...*/