Edit: I think this problem is not answered by this question, although likely related. In particular, if I use explicit instantiation instead of implicit by adding template class List<int*>
at the end of my test.cpp
file (I implemented this below), the problem persists. Or more precisely: I don't understand how to solve this problem. Thanks!
Solved: see below.
I am having a difficult time describing this problem, so apologies for the poor title.
I have a template class which contains a STL vector, and I am trying to implement some of the STL vector methods to make it feel like a vector. Most functions are fine but I ran into an isolated problem with the insert
function that takes another vector's iterators (i.e. "range" variant, see here):
template <class InputIterator>
iterator insert (const_iterator position, InputIterator first, InputIterator last);
One extra complication is that the template arguments to the class are pointers, e.g. a List<int*>
is a vector<int*>
rather than just a vector<int>
.
Here is the simplified header for the class:
test.hpp
#include <iostream>
#include <vector>
// Briefly declare List
template <typename T>
class List;
template <typename T>
class List<T*> {
public:
// Vector as list
typename std::vector<T*> _list;
// Constructor
List();
// Typedefs to hide that the iterators actually refer to the STL container
typedef typename std::vector<T*>::iterator iterator;
typedef typename std::vector<T*>::const_iterator const_iterator;
typedef typename std::vector<T*>::value_type value_type;
// Iterators
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
// Insert functions
// Single element
iterator insert (const_iterator position, const value_type& val);
// Range
template <typename InputIterator>
iterator insert (const_iterator position, InputIterator first, InputIterator last);
};
And here is it's implementation
test.cpp
#include "test.hpp"
// Constructor
template <typename T>
List<T*>::List() {};
// Iterators
template <typename T>
typename List<T*>::iterator List<T*>::begin() {return this->_list.begin();};
template <typename T>
typename List<T*>::const_iterator List<T*>::begin() const {return this->_list.begin();};
template <typename T>
typename List<T*>::iterator List<T*>::end() {return this->_list.end();};
template <typename T>
typename List<T*>::const_iterator List<T*>::end() const {return this->_list.end();};
// Single element insert function
template <typename T>
typename List<T*>::iterator List<T*>::insert (typename List<T*>::const_iterator position, const typename List<T*>::value_type& val)
{
return this->_list.insert(position,val);
};
// Range insert function
template <typename T>
template <typename InputIterator>
typename List<T*>::iterator List<T*>::insert (typename List<T*>::const_iterator position, InputIterator first, InputIterator last) {
return this->_list.insert(position,first,last);
};
// Explicitly instantiate a List<int*> class
template class List<int*>;
Now I write a simple program to test it:
run.cpp
#include "test.hpp"
int main() {
// Make two lists
List<int*> list_1;
List<int*> list_2;
// Add some elements
int i1 = 1;
int i2 = 2;
int i3 = 3;
int i4 = 4;
int i5 = 5;
// list_1 = [2,1]
list_1.insert(list_1.begin(), &i1);
list_1.insert(list_1.begin(), &i2);
// list_2 = [5,4,3]
list_2.insert(list_2.begin(), &i3);
list_2.insert(list_2.begin(), &i4);
list_2.insert(list_2.begin(), &i5);
// list_1 = [5,4,3,2,1]
list_1.insert(list_1.begin(),list_2.begin(),list_2.end());
for(auto const& value: list_1) {
std::cout << "list_1: " << value << " " << *value << std::endl;
};
return 0;
}
Compiling this with g++ run.cpp -std=c++14
gives me a symbol(s) not found for architecture x86_64
error.
However, if I copy and paste the entire int main()
to the end of the test.cpp
file, and then compile it with g++ run.cpp -std=c++14
, everything works as expected.
1) What is the remedy?
2) Why does this problem occur for only this variant of the insert function (the range variant)? For example, using only the single element variant works fine. My guess is it may be related to the use of two templates?
Thanks for your help!
Edit: solution based on the question marked as duplicating and the comments below.
I added:
template List<int*>::iterator List<int*>::insert (List<int*>::const_iterator position,
List<int*>::iterator first, List<int*>::iterator last);
at the bottom of test.cpp to create an explicit instantiation of this class method as well.
Lesson learned: if a template class has a template method, the template method also requires an explicit instantiation.