是否可以在C 中具有模板的单参数总和

Is it possible to have a templated, single-parameter sum function in C++?

本文关键字:单参数 参数 是否      更新时间:2023-10-16

在python中,我们可以做到这一点:

int_list = [1, 2, 3, 4, 5]
print(sum(int_list)) # prints 15
float_tuple = (1.2, 3.4, 9.9)
print(sum(float_tuple)) # prints 14.5

sum函数采用任何知道如何添加彼此并为0添加并产生总和的元素。

我想在C 11中发挥相同的功能。我知道存在accumulate方法,但是我想要一个采用单个参数的函数。本质上,我想知道如何编译以下代码:

#include <string>
#include <iostream>
#include <vector>
#include <deque>
#include <list>
template<typename iterable>
auto sum(iterable iterable_) {
    auto it = iterable_.begin();
    auto end = iterable_.end();
    if (it == end) {
        return 0;
    }
    auto res = *(it++); 
    while (it != end) {
        res += *it++;
    }
    return res;
}
int main() {
    std::vector<int> int_vector = {0, 1, 2, 3, 4, 5}; 
    std::cout << sum(int_vector) << 'n';    // prints 15
    std::deque<int> int_deque = {4, 5, 7};
    std::cout << sum(int_deque) << 'n';     // prints 16
    std::list<float> float_list = {1.2, 3.4, 9.9};
    std::cout << sum(float_list) << 'n';    // should print 14.5, but produces error.
}

此代码几乎有效。问题在于,auto看到return 0;的情况是在峰值为空的情况下,并且假设该函数必须返回int。然后看到float版本返回float,并感到困惑。有什么方法可以告诉编译器,如果 return float(0)看到 return稍后返回float

是的,您可以至少适用于标准容器。

标准容器定义了一个名为value_type的类型别名,用于该容器中存储的值类型。对于一个空容器,您可以返回此类型的值结构的对象:

template<typename iterable>
auto sum(iterable const &iterable_) {
    auto it = iterable_.begin();
    auto end = iterable_.end();
    if (it == end) {
        return typename iterable::value_type();
    }
    auto res = *(it++); 
    while (it != end) {
        res += *it++;
    }
    return res;
}

这确实取决于包含的类型是默认构造的,但这可能不是一个主要问题(当然适用于诸如intfloat之类的原始类型)。

如果您希望某些东西可以与任何 abor c 11范围(也就阵列以及具有免费beginend的容器,我们只能添加一些使用declarations并包装std::accumulate

template <class Range>
auto sum(Range&& range) {
    using std::begin;
    using std::end;
    using T = std::decay_t<decltype(*begin(range))>;
    return std::accumulate(begin(range), end(range), T{});
}

如果您不想包装accumulate,那么您也可以重新实现该循环以做同样的事情。

即使在非标准容器中也可以使用以下方法;只要某些东西以合理的方式实现begin()end()

#include <list>
#include <iostream>
#include <type_traits>
template<typename iterable>
auto sum(iterable && iterable_) {
    auto it = iterable_.begin();
    auto end = iterable_.end();
    typedef typename std::remove_reference<decltype(*it)>::type value_type;
    if (it == end) {
        return value_type(0);
    }
    auto res = *(it++);
    while (it != end) {
        res += *it++;
    }
    return res;
}
int main() {
    std::list<float> float_list = {1.2, 3.4, 9.9};
    std::cout << sum(float_list) << 'n';    // works now.
}