在一本关于C ++的书中,我找到了以下代码:
#include <iostream>
using namespace std;
template<class T> T sum(T* b, T* e, T init = T()) {
while(b != e)
init += *b++;
return init;
}
int main() {
int a[] = { 1, 2, 3 };
cout << sum(a, a + sizeof a / sizeof a[0]) << endl; // 6
}
我的模板函数T init = T()
的最后一个参数有什么用?
作者说以下关于第三个论点:
sum()的第三个参数是累积的初始值 元素。
但这怎么可行呢?拥有3个参数但只使用前两个参数不是一个坏习惯吗?这适用于所有类型或换句话说,是否在所有数据类型的C ++标准中定义了T()
?
注意:我从测试中知道它将init
初始化为0
。
答案 0 :(得分:3)
最后一个论点是初始值,我说。这个想法可能是你可以继续求和,或者不清楚零元素是什么。
这样的参数是所谓的默认参数,很常见。例如,如果您制作了自己的矢量类:
template <class T>
Vector(const unsigned int size, const T& default_value = (T) 0);
然后,您可以通过一个参数或两个Vector<double> vector(2);
或Vector<double> vector(2, 5.);
创建一个Vector对象。第一次调用产生一个大小为2的向量,该向量全为零,第二次调用大小为2的向量,所有条目为5。
在您的示例中,您可以为总和添加内容。
在您的情况下,调用标准构造函数,可能假设它是零元素。
那就是说,如果你的书倾向于使用指针算术,并且习惯先省略{} -brackets,然后甚至不使用缩进而忽略它们,我推荐另一本书。
答案 1 :(得分:2)
它被称为vue-loader
,它给它一个默认值。
粗略地说,对于值初始化,如果T是内置类型,那么它是零初始化的,如果它是类类型,那么将调用默认构造函数。
第三个参数用于此类用法:
cout << sum(a, std::end(a), 12) << endl; // 18
答案 2 :(得分:2)
但这怎么可行呢?
正如其他人所说,第三个参数将是默认构造的,或者在原语(如int
)的情况下,它将调用自由浮动函数,该函数将创建,初始化并返回一个值0
。
拥有3个参数但只使用前两个参数是不是一个坏习惯?
不一定。我的意思是,大多数语言都存在默认参数。它有助于减少打字量和心理开销。此外,有时开发人员确实知道一个好的&#34;参数的默认值。在求和的情况下,通常人们想要从0
开始,并且通常在基元上调用求和。
这适用于所有类型,换句话说,是否在所有数据类型的C ++标准中定义了T()?
不,不是。您可以创建必须使用某些参数构造的任意类型。在这种情况下,您不得不自己提供第三个参数。例如:
struct IntHolder
{
int value = 0;
IntHolder(int _init) : value(_init){}
IntHolder& operator+=(const IntHolder& other)
{
value += other.value;
return *this;
}
};
template<class T> T sum(T* b, T* e, T init = T()) {
while(b != e)
init += *b++;
return init;
}
int main() {
std::vector<IntHolder> a{1,2,3};
cout << sum(a.data(), a.data()+a.size(), IntHolder(0)).value << endl; // 6
}
答案 3 :(得分:1)
以这种方式指定泛型参数的一个非常有用的功能是,相同的代码可以应用于非数字类型,前提是它们支持默认构造函数和operator+=
:
#include <iostream>
#include <string>
template<class T> T sum(T* b, T* e, T init = T()) {
while(b != e)
init += *b++;
return init;
}
int main() {
std::string a[] = { "the ", "cat ", "sat ", "on ", "the ", "mat" };
std::cout << sum(a, a + sizeof a / sizeof a[0]) << std::endl;
}
但是,作者应该在迭代器方面实现泛型函数,因为它的限制性较小:
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <array>
//
// better - now works with all forward iterator models, including pointers
//
template<class Iter, class T = typename std::iterator_traits<Iter>::value_type>
T sum(Iter b, Iter e, T init = T()) {
while(b != e)
init += *b++;
return init;
}
int main() {
std::string a[] = { "the ", "cat ", "sat ", "on ", "the ", "mat" };
std::cout << sum(a, a + sizeof a / sizeof a[0]) << std::endl;
std::cout << sum(std::begin(a), std::end(a)) << std::endl;
std::vector<int> vi = { 1, 2, 3, 4, 5, 6 };
std::cout << sum(std::begin(vi), std::end(vi)) << std::endl;
std::array<int, 6> ai = { 1, 2, 3, 4, 5, 6 };
std::cout << sum(std::begin(ai), std::end(ai)) << std::endl;
}
答案 4 :(得分:0)
使用第三个参数,您可以指定累积的初始量。试试这个:
cout << sum(a, a + sizeof a / sizeof a[0], 10); //16
答案 5 :(得分:0)
你如何写一个(微不足道的)整数数组?可能是这样的:
int sum = 0;
for (int i=0; i<length; i++) sum = sum+t[i];
如果您有T
个数组(包含适当的运算符+
,=
),则更“通用”:
T sum = T();
for (int i=0; i<l; i++) sum = sum+t[i];
当然,您需要的(稍微更通用)是为sum
提供您想要的任何第一(初始)值。这就是为什么第三个参数存在默认值,让您忽略它。
并非所有类都提供了一个没有参数的ctor可调用,但是在C ++非正式编程规则中存在 canonical 类的概念,你必须提供一个没有参数的ctor可调用,因此默认值。