0

Let's say we have a class with a function template.

Header file Sort.hpp with the class definition:

#ifndef TEST_SORT_HPP
#define TEST_SORT_HPP

#include <vector>
using namespace std;

class Sort {
public:
    template <typename T>
    static void mergeSort(vector<T>& arr);
};

#endif //TEST_SORT_HPP

Source file Sort.cpp with the function implementation:

#include "Sort.hpp"

template <typename T>
void Sort::mergeSort(vector<T> &arr) {
    // the implementation is irrelevant at the moment
}

This structure would not work for reasons stated in this answer. As also stated in the referenced answer, there are ways to work around this issue, if I do not want to include the implementations straight into the header file.

However, those solutions do not work for me:

  • If I add #include "Sort.cpp" in the end of the header file (before #endif), I get the error: redefinition of 'static void Sort::mergeSort(std::vector<T>&)'

  • I do not know in advance all the types the sort is used for and cannot declare them explicitly in the end of the source file.

  • I also cannot remove #include "Sort.hpp" from the Sort.cpp file, because then 'Sort' has not been declared

How is this actually done to make it work?

What are the best practices for organizing code into files in case of:

  • ... creating class templates with unknown types (unlimited)?

  • ... creating class templates where it is known which certain types will be used?

Snackoverflow
  • 5,332
  • 7
  • 39
  • 69
  • I don't understand, why don't you just implement in the header as suggested in the linked answer? – user202729 Oct 27 '18 at 10:20
  • The linked answer also suggests different solutions, **which do not work**. And this question is falsely marked as a duplicate, since it asks how to actually do it correctly and what are the best design patterns. For your question, the reason is the same as the reason for keeping .hpp and .cpp files separate in the first place, the separation of class definitions and their implementation is a widely used style in C++. – Snackoverflow Oct 27 '18 at 10:25
  • The "correct" way *is* to define (implement) templated functions in the header file. If you want to keep declaration and definition in separate files, create two header files, and include the header file with the definitions at the end of the "normal" header file. – Some programmer dude Oct 27 '18 at 10:29
  • Alright, so the most common design approach is to *not* keep implementation separate? – Snackoverflow Oct 27 '18 at 10:30
  • 1
    @anddero Keeping template definition code in a`.cpp` file is theoretically possible, but screws up most build systems. At least you should use a different file extension like `.tcc` or whatever. This is also explained well in the answers at the duplicate link. – πάντα ῥεῖ Oct 27 '18 at 10:31
  • 1
    The linked answer already said "A common solution to this is to write the template declaration in a header file, then implement the class in an implementation file (for example .tpp), and include this implementation file at the end of the header.". – user202729 Oct 27 '18 at 10:34
  • Alright, thanks, I have tried it and it works. The answer just does not emphasize the need for a different extension. The only thing I changed is '.cpp' to '.tpp', which seems weird to me because it is just an extension... – Snackoverflow Oct 27 '18 at 10:37
  • @anddero _" which seems weird to me because it is just an extension."_ Well, build systems know from file extensions what to do with them. – πάντα ῥεῖ Oct 27 '18 at 10:52
  • Why do you want that function to be a template? How does its implementation depend on `T` anyway? – Toby Speight Oct 30 '18 at 16:56
  • @TobySpeight I want it to be a template, for it to work on a vector of any types of objects. The implementation depends on `T` the way the comparison operator *less-than* is implemented for the type `T`. (Note, this is just a general question, I know about the existence of `std::algorithm`. There are many use cases of template functions.) – Snackoverflow Oct 30 '18 at 17:39
  • 1
    But it accepts a vector of `int` - nothing there is dependent on `T`. If you want it to work on a vector of objects of any type, you'd need to write `vector` instead. – Toby Speight Oct 30 '18 at 17:40
  • Must have been a typo, but I guess the compiler did not notice either ;) But I have edited the question for completeness, thanks. – Snackoverflow Oct 30 '18 at 17:41

0 Answers0