Sum of vector of vectors of vectors ... of integers

Viewed 733

I'm trying to sum all the elements of a vector of vectors of vectors ... of integers: something like a std::vector<std::vector<std::vector<std::vector<int>>>> where there's no need to every layer have the same size.

I would like to accomplish it using template, so I did it:

namespace nn
{
    template < class T >
    int sumAllElements(std::vector<T> v)
    {
        int size = v.size();
        int output = 0;

        for ( int i = 0 ; i < size ; i++ )
        {
                                                //should call the function below 
            output += sumAllElements( v[ i ] ); //or this function, depending in 
                                                //which "layer" we are
        }

        return output;
    }

    int sumAllElements(std::vector<int> v)
    {
        int size = v.size();
        int output = 0;

        for ( int i = 0 ; i < size ; i++ )
        {
            output += v[ i ]; //we've reached the bottomest layer,
                              //so just sum everybory
        }

        return output;
    }
}

BUT, this is happening:

CMakeFiles\test.dir/objects.a(main.cpp.obj): In function `main':
D:/test/main.cpp:49: undefined reference to `int nn::sumAllElements<std::vector<int, std::allocator<int> > >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >)'
collect2.exe: error: ld returned 1 exit status
mingw32-make.exe[3]: *** [CMakeFiles\test\build.make:141: test.exe] Error 1
mingw32-make.exe[2]: *** [CMakeFiles\Makefile2:67: CMakeFiles/test.dir/all] Error 2
mingw32-make.exe[1]: *** [CMakeFiles\Makefile2:79: CMakeFiles/test.dir/rule] Error 2
mingw32-make.exe: *** [Makefile:117: test] Error 2

I really don't know why...

Thanks in advance.

3 Answers

You can't call a function that hasn't been declared yet. Templates can sometimes make that problem go away, but not always. And this is one of the cases where you simple need a declaration of int sumAllElements(std::vector<int> v) prior to template < class T > int sumAllElements(std::vector<T> v)

Reading your error message. It looks like your functions are in a separate compilation unit from main.cpp. If your functions are in a .h file, #include the header file in main.cpp.

I would suggest using the template specialization declaration:

template<>
int sumAllElements(std::vector<int> v)
{
 ...   
}

Another, unrelated suggestion, would be to pass the vectors by const reference. Currently, you are passing them by value which could be costly if the vectors are large.

You can use SFINAE to enable/disable the specialization that is needed:

template <class T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
auto sum_all(const std::vector<T>& v)
{
    T sum = 0;

    for (auto& e : v)
    {
        sum += e;
    }

    return sum;
}

template <class T, std::enable_if_t<!std::is_arithmetic<T>::value, int> = 0>
auto sum_all(const std::vector<T>& nested_v)
{
    decltype(sum_all(nested_v[0])) sum = 0;

    for (auto& e : nested_v)
    {
        sum += sum_all(e);
    }

    return sum;
}

See it on coliru


With C++17 you can have just one function (neat!):

template <class T>
auto sum_all(const std::vector<T>& nested_v)
{
    innermost_type_t<T> sum = 0;

    for (auto& e : nested_v)
    {
        if constexpr(std::is_arithmetic<T>::value)
            sum += e;
        else
            sum += sum_all(e);
    }

    return sum;
}

With innermost_type_t defined as:

template <class T> struct innermost_type
{
    using type = T;
};

template <class T> struct innermost_type<std::vector<T>>
{
    using type = typename innermost_type<T>::type;
};

template <class T>
using innermost_type_t = typename innermost_type<T>::type;
Related