c++ - C++中各种类型任意嵌套可迭代实现的求和函数
问题描述
正如标题所提到的,我正在尝试实现一个求和函数,它可以处理 C++ 中各种类型的任意嵌套可迭代事物。这里的各种类型包括可以加在一起的类型,这里任意嵌套的可迭代事物包括任何具有begin()
and的东西end()
,例如std::vector
and 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
但是,上述功能存在一些缺陷
可迭代案例的实现中的返回值类型始终为
long double
。看起来这个返回类型应该和输入的可迭代值类型一样。对于
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>>>
。这个问题有什么可能的解决方案吗?
欢迎所有建议。
解决方案
您只需要更聪明地推导以下类型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
参数,因此该部分失败。