Could you tell me how the template class is divided between cpp and hpp files so that it is correct?

For example, now I have persistentmap.hpp and persistentmap.cpp

This class is in persistentmap.hpp :

 template <class Key, class FileType, class Compare = std::less<Key>> class PersistentMap { public: typedef int size_type; typedef std::pair<Key, FileType> value_type; typedef FileType mapped_type; typedef AVL_Tree<Key, FileType> tree; typedef PersistentMapProxy<Key, mapped_type, Compare> Proxy; private: std::string dirName; tree *strom; Compare comp; public: typedef typename tree::iterator iterator; typedef typename tree::const_iterator const_iterator; //iterators iterator begin() { //iterator::a = t; return strom->begin(); } iterator end() { return strom->end(); } //constructors PersistentMap(std::string ag) :dirName(ag) { //boosttrap path p(ag); if (!fs::exists(p)) fs::create_directory(ag); strom=new tree(dirName); }; ~PersistentMap() { delete strom; } //operators const Proxy operator[] (Key key) { return Proxy(*this, key); } //methods std::pair<iterator, bool> insert(const value_type& a) { int count = strom->getCount(); iterator it = iterator(strom->insert(a)); if (count< strom->getCount()) return std::make_pair(it, true); else return std::make_pair(it, false); } iterator find(const Key& a) { return iterator(*strom->findKey(a)); } const_iterator find(const Key& a) const { return const_iterator(*strom->findKey(a)); } iterator erase(const_iterator a) { iterator prev = a++; erase((*prev).first); return a; } void erase(iterator first, iterator last) { iterator it; iterator prev= first++; for (it = first; it != last; prev=it++) { strom->erase((*prev).first); } strom->erase((*prev).first); } size_type erase(const Key& k) { strom->erase(k); return strom->getCount(); } }; 

Whereas persistentmap.cpp empty.

I understand that in a good way the body of functions needs to be brought out of the limits of hpp, but I cannot imagine how to do it correctly.

I would be very happy with the example and possible explanation.

    2 answers 2

    Start over. When you define a regular class:

     class test { int _a; public: void set(int a); int get(a); } 

    When implementing methods outside the class, specify the class to which they belong:

     void test::set(int a) { _a = a; } int test::get() { return _a; } 

    When using a template class:

     template<class T> class test { T _a; public: void set(T a); T get(a); } 

    Then you need to describe the template and also its parameters when specifying the class:

     template<class T> void test<T>::set(T a) { _a = a; } template<class T> T test<T>::get() { return _a; } 

    And now an important point to pay attention to. The template class should not be implemented in the cpp file, the implementation should be included along with the class description in the stub file, otherwise you will get a compile error Undefined symbols . The reason is that template classes, functions themselves do not exist, they are created when compiling with the types that you use in your code. If the implementation of the methods is not described before using the template, then it is not created for the necessary types, hence the error.

    Therefore, to separate the implementation of the template class you need to use a different approach. I, for example, do a class declaration in a file like test.h , and the implementation in test.hpp . In this case, after the class declaration, the first file contains the line #include "test.hpp" , so that the implementation of the template methods will always be together with the description of the template class itself.


    You can store methods in the cpp file. In this case, Ba will simply manually instantiate the template with the desired types. You can simply specify a method. For the class above, an example is:

     template void test<int>::set(int a); 

    Or specify only the class:

     template class test<std::string>; 
    • but what if I make a template class for a task, and in a solution there are tasks both cpp and hpp - Demolver
    • It is possible and so now supplemented. - AivanF.
    • @Demolver take a look. - AivanF.
    • and if I do like this template <class Key, class value, class Compare> Map<Key, value, Compare>::Map() { //тело }; that is, I sort of created templating from above for the implementation of the body function - Demolver
    • @Demolver yes, this is what you need. - AivanF.

    In this case, this is not required, since you have a template class. All templates are instantiated in the place where concrete types and constants are substituted into it. And this happens, as you understand, in other translation units, that is, in other .cpp files. Instantiation means that the compiler generates a specific type implementation using this template.

    And the file persistentmap.cpp is not needed at all and needs to be deleted.

    • I am told by the assignment that you need to fill both files, and hpp and cpp? What can you advise in this case? - Demolver