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

Vin*_*ent 36 c++ templates stl default-arguments c++14

C++ 14标准为以下内容指定了以下声明std::exchange:

template <class T, class U = T>
T std::exchange(T& obj, U&& new_value);
Run Code Online (Sandbox Code Playgroud)

我想知道为什么U违约,T因为U可以找到感谢new_value.在什么情况下,这会导致与以下结果不同的结果:

template <class T, class U>
T std::exchange(T& obj, U&& new_value);
Run Code Online (Sandbox Code Playgroud)

Tem*_*Rex 39

std::exchange在提出N3511 没有默认模板参数,后来N3608有默认模板参数.请注意,在N3608中提供了以下推理:

为第二个模板参数提供默认值可修复以下两种情况:

DefaultConstructible x = ...;
if (exchange(x, {})) { ... }

int (*fp)(int);
int f(int);
double f(double);
/*...*/ exchange(fp, &f) /*...*/
Run Code Online (Sandbox Code Playgroud)

第一个例子的有用性当然{}是推导出一个无类型的临时值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>(例如,标准算法).

  • @JonathanMee,基本功能重载!? (6认同)
  • @JonathanMee,不,它指向一个`int(int)`函数.`f`的第一次重载.... (2认同)

Vla*_*cow 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;
}
Run Code Online (Sandbox Code Playgroud)

输出是

a: 1 2 3 
b: 4 5 6 
sum = 6
a: 4 5 6 
Run Code Online (Sandbox Code Playgroud)

或者示例可以包括转换

#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;
}
Run Code Online (Sandbox Code Playgroud)