我使用std :: accumulate作为编码练习的一部分,并且遇到了一些我想要更全面理解的行为。
累积的签名是:
T accumulate( InputIt first, InputIt last, T init );
如果我的代码如下:
std::vector<int> a = {..};
int64_t zero = 0;
int64_t csum = std::accumulate(a.begin(), a.end(), zero);
它像我期待的那样有效。如果我将其更改为:
std::vector<int> a = {..};
int64_t csum = std::accumulate(a.begin(), a.end(), 0);
然后我得到溢出,因为(我认为)&#39; 0&#39;被确定为32位整数,并且这会覆盖我实际指定的返回类型(因为普通整数可以存储在64位整数中)。
由此我推断编译器正在生成一个类似于:
的累积int accumulate( InputIt first, InputIt last, int init );
VS
int64_t accumulate( InputIt first, InputIt last, int64_t);
是否有一些规则可以记住将这种推断推广到其他案例?
答案 0 :(得分:1)
累积的签名是:
T accumulate( InputIt first, InputIt last, T init );
累积的签名是
template< class InputIt, class T >
T accumulate( InputIt first, InputIt last, T init );
别忘了模板参数!如果总是必须指定类型,模板将是一种皇家的痛苦。编译器(有时)很好地推断出那些模板参数是基于你提供的参数。
这是可以并且确实这样做的情况之一。在这种情况下,它会推断InputIt
是std::vector<int>::iterator
而T
是std::int64_t
(您的第一个示例)或int
(您的第二个示例)。< / p>
除非您告诉编译器,否则它始终会将0
推断为类型int
。有一种方法可以告诉编译器0
是其他类型的:
std::accumulate(a.begin(), a.end(), 0L) // T is long int
std::accumulate(a.begin(), a.end(), 0LL) // T is long long int
std::accumulate(a.begin(), a.end(), 0U) // T is unsigned int
std::accumulate(a.begin(), a.end(), 0UL) // T is unsigned long int
std::accumulate(a.begin(), a.end(), 0ULL) // T is unsigned long long int