C ++ 14标准为std::exchange
指定了以下声明:
template <class T, class U = T>
T std::exchange(T& obj, U&& new_value);
我想知道为什么U
默认为T
,因为U
可以找到new_value
。在这种情况下,这会导致与以下结果不同的结果:
template <class T, class U>
T std::exchange(T& obj, U&& new_value);
答案 0 :(得分:39)
在N3511 中提出了std::exchange
,没有默认模板参数,后来N3608提出了默认模板参数。请注意,在N3608中提供了以下推理:
为第二个模板参数赋予默认值可以修复 以下两种情况:
DefaultConstructible x = ...; if (exchange(x, {})) { ... } int (*fp)(int); int f(int); double f(double); /*...*/ exchange(fp, &f) /*...*/
第一个示例的有用性当然是将无类型的临时{}
推断为T
。第二个例子涉及更多:
14.8.2模板参数推断[temp.deduct]
5使用得到的替换和调整的函数类型作为 模板参数推导的函数模板的类型。 如果是 模板参数尚未推断及其对应的模板 参数有一个默认参数,确定模板参数 通过替换为前面确定的模板参数 模板参数进入默认参数。如果替换 导致无效类型,如上所述,类型扣除失败。
14.8.2.5从类型[temp.deduct.type]中扣除模板参数
4在大多数情况下,类型,模板和非类型值都是 用来组成P参与模板参数推导。那是, 它们可用于确定模板参数的值,以及 如此确定的值必须与确定的值一致 别处。然而,在某些情况下,价值却没有 参与类型推导,但改为使用模板的值 在别处推断或明确指定的参数。 如果模板参数仅在非推导的上下文中使用,则为 未明确指定,模板参数推断失败。
5未推断的上下文是:
(5.5) - 不能进行参数推导的函数参数 完成因为关联的函数参数是一个函数,或一个集合 重载函数(13.4),以及以下一项或多项 申请:
(5.5.1) - 多个函数与函数参数匹配 输入(导致扣除不明确)
在第二个示例中,模板参数U
仅用于非推断的上下文,因为两个重载f(int)
和f(double)
都可以与U
匹配。因此,不会发生参数推断,U
成为T
的提供默认值(在这种情况下为int (*)(int)
,因此选择f(int)
。)
此外,正如@VladfromMoscow所解释的那样,具有默认参数允许在传递std::exchange<T>
(例如标准算法)时更短的代码。
答案 1 :(得分:10)
该函数可以作为参数传递给其他函数或例如算法。在这种情况下,如果函数的两个参数具有相同的类型,则仅指定第一个模板参数就足够了。
这使代码更简短,更易读。
这是一个人为的例子。:)
#include <iostream>
#include <numeric>
#include <iterator>
#include <functional>
int main()
{
int a[] = { 1, 2, 3 };
int b[] = { 4, 5, 6 };
std::cout << "a: ";
for ( int x : a ) std::cout << x << ' ';
std::cout << std::endl;
std::cout << "b: ";
for ( int 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<int>(), std::exchange<int> );
std::cout << "sum = " << sum << std::endl;
std::cout << "a: ";
for ( int x : a ) std::cout << x << ' ';
std::cout << std::endl;
}
输出
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;
}