2

My Initial implementation approach in .cpp is like the following:

using namespace std;
...
template <typename T>
void print2dvector(vector<vector<T> > v) {
    for(int i = 0; i < v.size(); i++) {
        for(int j = 0; j < v[i].size(); j++) {
            cout << v[i][j] << " ";
        }
        cout << endl;
    }
}

The declaration in .h file is the following

template <typename T> void print2dvector(std::vector<std::vector<T> > v);

Here is how I use it,

print2dvector<int>(vec_of_vec);

The compile stage passes, but failed in linking stage. The error is the following:

Undefined symbols for architecture x86_64:
  "void print2dvector<int>(std::__1::vector<std::__1::vector<int, std::__1::allocator<int> >, std::__1::allocator<std::__1::vector<int, std::__1::allocator<int> > > >)", referenced from:
   spiral_matrix_ii_Challenge::Execute() in spiral_matrix_ii.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Please let me know if I miss anything conceptually in implementing this.

lordofire
  • 145
  • 2
  • 13

1 Answers1

5

Linking errors means that your template was not instantiated and linker was not able to link the symbols. As @Piotr Skonticki told, the best option to fix this is to implement it in the place of use or in the header file. See this for more information.

About the code - I'd write it like this:

#include <vector>
#include <iterator>
#include <algorithm>
#include <iostream>

template<typename T>
void printVector(const T& t) {
    std::copy(t.cbegin(), t.cend(), std::ostream_iterator<typename T::value_type>(std::cout, ", "));
}

template<typename T>
void printVectorInVector(const T& t) {
    std::for_each(t.cbegin(), t.cend(), printVector<typename T::value_type>);
}

int main() {
    std::vector<int> a = {1, 3, 5, 7, 9};
    std::vector<std::vector<int>> b;
    b.push_back(a);
    b.push_back(a);
    printVectorInVector(b);
    return 0;
}

I think this is better than your solution because:

  1. It does not rely on a iterable collection type (it can be vector, list, or anything that has iterators and stl-like iterator interface).
  2. It does not rely on value type - it always gets proper value type from iterable collection (T::value_type).
  3. It also avoids object copying because it gets it by a const reference.
Community
  • 1
  • 1
VP.
  • 15,509
  • 17
  • 91
  • 161