C++ 如何对多维std::vector的所有元素求和?

C++ 如何对多维std::vector的所有元素求和?,c++,multidimensional-array,metaprogramming,stdvector,C++,Multidimensional Array,Metaprogramming,Stdvector,想法简单明了: 继续将n维度向量分解为n-1维度组成向量,直到您能够访问基本数据类型对象。然后把它们全部加起来 问题是,如何推断退货类型? 可以这样做,但它已经假定求和变量的数据类型(返回类型): typedef int-SumType; 模板 T总和(常数T x) { 返回x; } 模板 SumType总和(常数标准::向量和v) { SumType sum=0; 用于(常数自动和x:v) 总和+=总和(x); 回报金额; } 但我不想像上面那样做。我觉得这违背了元编程的精神 我们必须通过

想法简单明了:
继续将
n
维度向量分解为
n-1
维度组成向量,直到您能够访问基本数据类型对象。然后把它们全部加起来

问题是,如何推断退货类型?

可以这样做,但它已经假定求和变量的数据类型(返回类型):

typedef int-SumType;
模板
T总和(常数T x)
{
返回x;
}
模板
SumType总和(常数标准::向量和v)
{
SumType sum=0;
用于(常数自动和x:v)
总和+=总和(x);
回报金额;
}

但我不想像上面那样做。我觉得这违背了元编程的精神

我们必须通过不断将向量分解为其组成向量来推断返回类型,直到到达基本数据类型对象,然后选择返回类型作为基本数据类型

< C++中有可能吗?(我是元编程的noob)


附加说明
中的
std::acculate()
可能会有所帮助,但它通过从第三个参数
\uu init
推断返回类型来绕过问题,我们可以使用的是获取基础类型的。这被定义为

那么你可以用

int main()
{
    std::cout << Sum(std::vector<std::vector<std::vector<int>>>{{{1},{2},{3}},{{4},{5},{6}}});
}

这可以在没有任何模板元编程的情况下完成。您可以让编译器使用
auto
decltype
推断类型:

template <class T>
T Sum(const T x) {
    return x;
}

template <class T>
auto Sum(const std::vector<T> &v) {
    decltype(Sum(v[0])) sum = 0;
    for (const auto &x : v)
        sum += Sum(x);
    return sum;
}
模板
T总和(常数T x){
返回x;
}
模板
自动求和(const std::vector&v){
decltype(Sum(v[0]))Sum=0;
用于(常数自动和x:v)
总和+=总和(x);
回报金额;
}
Sum
的返回类型是从
Sum
自动推导出来的,并且
Sum
的类型是任何
Sum(v[0])
返回的类型。最终您将得到第一个版本的
Sum
,它返回
T
,编译器知道该类型


你几乎已经自己找到了答案。请注意这一行:

sum += Sum(x);
我们所追求的
sum
类型必须与递归调用
sum
的结果相兼容。根据您的需求,其中一种类型肯定是调用的结果类型

我们不必仅仅依靠模糊的感觉。毕竟,元编程就是编程。你可能没有意识到这一点,但你的问题是一个有充分根据的递归,这意味着归纳原理可以引导我们找到答案

  • 在基本情况下,我们有一个数值的、非向量的
    元素\u类型元素
    ,表示我们的结果类型是…
    元素类型
    。事实上,您已经完成了此步骤,这是第一个过载:

    template<typename T>
    T Sum(T element);
    
    由于向量元素具有type
    element\u type
    ,归纳假设为我们提供了对它们调用
    Sum
    的结果具有我们想要的所有属性。(我们的
    +=
    直觉的理由来源于此。)我们有自己的答案:我们按原样使用
    递归结果类型

现在,第二个重载不能只写,例如:

// doesn't behave as expected
template<typename Element>
auto Sum(std::vector<Element> const& vec) -> decltype( Sum(vec.front()) );

SumType必须在编译时可推断,就像使用模板一样,以便编译器知道要生成哪些函数原型。您可以查看
decltype
,从基础数据定义SumType的返回值。要获得更灵活的解决方案,请查看如何将基本数据包装到脚本语言中的变量类中。您可能需要
SumType sum{}
。没有明显的理由假设数字0可以转换为
SumType
template <class T>
T Sum(const T x) {
    return x;
}

template <class T>
auto Sum(const std::vector<T> &v) {
    decltype(Sum(v[0])) sum = 0;
    for (const auto &x : v)
        sum += Sum(x);
    return sum;
}
sum += Sum(x);
template<typename T>
T Sum(T element);
// given
element_type element;
// we know the following is well-formed and a numerical type
using recursive_result_type = decltype( Sum(element) );
// doesn't behave as expected
template<typename Element>
auto Sum(std::vector<Element> const& vec) -> decltype( Sum(vec.front()) );
// defining a functor type with operator() overloads
// would work just as well
struct SumImpl {
    template<typename Element>
    static T apply(Element element)
    { return element; }

    template<typename Element>
    static auto apply(std::vector<Element> const& vec)
    -> decltype( apply(vec.front()) )
    {
        using result_type = decltype( apply(vec.front()) );
        result_type sum = 0;
        for(auto const& element: vec) {
            sum += apply(element);
         }
         return sum;
    }
};

template<typename Arg>
using sum_result_t = decltype( SumImpl::apply(std::declval<Arg const&>()) );

template<typename Arg>
sum_result_t<Arg> Sum(Arg const& arg)
{ return SumImpl::apply(arg); }