首页 > 解决方案 > C++中各种类型任意嵌套可迭代实现的求和函数

问题描述

正如标题所提到的,我正在尝试实现一个求和函数,它可以处理 C++ 中各种类型的任意嵌套可迭代事物。这里的各种类型包括可以加在一起的类型,这里任意嵌套的可迭代事物包括任何具有begin()and的东西end(),例如std::vectorand std::array

template<typename T>
concept Summable = requires(T x) { x + x; };

template<typename T>
concept Iterable = requires(T x)
{
    x.begin();      // must have `x.begin()` 
    x.end();        // and `x.end()` 
};

template<typename T> requires Summable<T>
static T Sum(T inputNumber);        //  Deal with the base case like "Sum(static_cast<int>(1))"

template<class T> requires Iterable<T>
static auto Sum(const T& numbers);  //  Deal with the iterable case like "Sum(std::vector<long double>{ 1, 1, 1 })"


template<class T> requires Summable<T>
static inline T Sum(T inputNumber)
{
    return inputNumber;
}

template<class T>  requires Iterable<T>
static inline auto Sum(const T& numbers)
{
    long double sumResult = 0.0;
    for (auto& element : numbers)
    {
        sumResult = sumResult + Sum(element);
    }
    return sumResult;
}

测试用例如下所示。

long double testNumber = 1;
    
std::vector<decltype(testNumber)> testVector1;
testVector1.push_back(testNumber);
testVector1.push_back(testNumber);
testVector1.push_back(testNumber);
std::cout << Sum(testVector1) << std::endl;

std::vector<decltype(testVector1)> testVector2;
testVector2.push_back(testVector1);
testVector2.push_back(testVector1);
testVector2.push_back(testVector1);
std::cout << Sum(testVector2) << std::endl;

std::vector<decltype(testVector2)> testVector3;
testVector3.push_back(testVector2);
testVector3.push_back(testVector2);
testVector3.push_back(testVector2);
std::cout << Sum(testVector3) << std::endl;

//  std::array test case
std::array<long double, 90> numberArray;
for (size_t i = 0; i < 90; i++)
{
    numberArray[i] = 1;
}
std::cout << std::to_string(Sum(numberArray)) + "\n";

Sum但是,上述功能存在一些缺陷

  1. 可迭代案例的实现中的返回值类型始终为long double。看起来这个返回类型应该和输入的可迭代值类型一样。

  2. 对于std::complex非内置数值类型的类型,该sum功能不起作用。

我尝试将Sum函数修改为以下版本。

template<class T>  requires Iterable<T>
static inline auto Sum(const T& numbers)
{
    typename std::iterator_traits<T::iterator>::value_type sumResult = 0.0;     //  Update "long double" into "typename std::iterator_traits<T::iterator>::value_type"
    for (auto& element : numbers)
    {
        sumResult = sumResult + Sum(element);
    }
    return sumResult;
}

然后,它可以很好地std::vector<>以防万一。但是,typename std::iterator_traits<T::iterator>::value_type不能处理多嵌套的可迭代情况,例如std::vector<std::vector<std::complex>>or std::vector<std::vector<std::vector<std::complex>>>。这个问题有什么可能的解决方案吗?

欢迎所有建议。

标签: c++recursionc++20c++-concepts

解决方案


您只需要更聪明地推导以下类型sumResult

template<class T>  requires Iterable<T>
static inline auto Sum(const T& numbers)
{
    typedef typename std::iterator_traits<typename T::iterator>::value_type
        value_type;

    decltype(Sum(std::declval<value_type &&>())) sumResult{};

    for (auto& element : numbers)
    {
        sumResult = sumResult + Sum(element);
    }
    return sumResult;
}

通过此更改,显示的代码编译为

std::complex<double> testNumber{1,0};

并且还编译了涉及 a 的计算

std::array<std::complex<double>, 90> numberArray;

但是,没有合适的重载来std::to_string接受std::complex参数,因此该部分失败。


推荐阅读