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++ 在std::exchange中,为什么第二个模板参数是默认的?_C++_Templates_Stl_C++14_Default Arguments - Fatal编程技术网

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

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>

C++14标准为
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) /*...*/