Is there any difference to implement in class definition for headings only?

I am working on a library that uses templates a lot, so I decided to make it a library for headers only. Since declarations and implementations are in the same file, I can do both at the same time. Therefore, I have a choice between these two styles:

// seperate declaration and implementation template <typename T> class Klass { public: void do_something(); }; template <typename T> void Klass<T>::do_something() { // do something } // or both at the same time template <typename T> class Klass { public: void do_something() { // do something } }; 

I was wondering if there is a difference between the two for the compiler. If you would not recommend as a best practice?

+6
source share
1 answer

If you combine definition and implementation, you will have problems resolving cross-circular dependencies.



For instance:

1. Using the second option

home.hpp

 #ifndef HOME_HPP # define HOME_HPP # include <string> # include "human.hpp" template <typename T> class Home { public: Home() : color_("white"), inhabitant_(this) { } void set_color(const std::string& color) { color_ = color; } private: std::string color_; Human<T> inhabitant_; }; #endif 

human.hpp

 #ifndef HUMAN_HPP # define HUMAN_HPP # include <string> // Cannot include the other header here because it already includes us //# include "house.hpp" // So we do a forward declaration: template<typename T> class Home; template <typename T> class Human { public: Human(Home<T>* house) : house_(house) { } void paint(const std::string& color) { // Oops, we can't use House in our implementation // because it is only forward declared //house_->set_color(color); } private: Home<T>* house_; }; #endif 

You cannot use another object.



If you split your implementation in another file:

2. Using the first option

home.hpp

 #ifndef HOME_HPP # define HOME_HPP # include <string> # include "human.hpp" template <typename T> class Home { public: Home(); void set_color(const std::string& color); private: std::string color_; Human<T> inhabitant_; }; #endif 

home.ipp

 #ifndef HOME_IPP # define HOME_IPP # include "home.hpp" template<typename T> Home<T>::Home() : color_("white"), inhabitant_(this) { } template<typename T> void Home<T>::set_color(const std::string& color); { color_ = color; } #endif 

human.hpp

 #ifndef HUMAN_HPP # define HUMAN_HPP # include <string> template<typename T> class Home; template <typename T> class Human { public: Human(Home<T>* house); void paint(const std::string& color); private: Home<T>* house_; }; #endif 

human.ipp

 #ifndef HUMAN_IPP # define HUMAN_IPP # include "human.hpp" # include "house.ipp" template<typename T> Human<T>::Human(Home<T>* house) : house_(house) { } template<typename T> void Human<T>::paint(const std::string& color) { house_->set_color(color); } #endif 

Everything works more smoothly



3. Other considerations

  • You could also argue that you should put your code in multiple files for the same reason that you are not encoding the entire project in one file, just to separate things to make them more understandable.
  • And as the last bonus point for symmetry with .hpp / .cpp files, which will make the perfectionist sleep deeply (very deeply for some) inside each developer :)
+2
source

Source: https://habr.com/ru/post/975419/


All Articles