在std :: exchange中,为什么第二个模板参数是默认的?

时间:2016-01-19 12:34:27

标签: 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);

我想知道为什么U默认为T,因为U可以找到new_value。在这种情况下,这会导致与以下结果不同的结果:

template <class T, class U>
T std::exchange(T& obj, U&& new_value);

2 个答案:

答案 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;
}