简体   繁体   中英

Is it a good practice to not to separate function declarations and definitions for templated classes?

Generally in non templated classes, we separate the function declarations and definitions into separate files (.h and .cpp)

[1] But the above practice does not seem to work very good with templated classes. Is it advised to write implementations in a separate file and then include it at the bottom of .h file ?

[2] Which of the below scheme is generally advised for templated classes?
[a] declarations and definition all at once or
[b]seperated declarations & definitions in the same file

Given the complicated syntax that we have to take care of if we go by choice [b]

Eg. [a]

template <typename T>
class unique_ptr final {
  private:
    T* ptr_;
  public:
    unique_ptr (T* ptr = nullptr) noexcept {
      : ptr_{ ptr } {
    }

    friend bool operator == (const unique_ptr& lhs, const unique_ptr& rhs) {
      return lhs.get() == rhs.get();
    }
};

[b]

template <typename T>
class unique_ptr final {
  private:
    T* ptr_;
  public:
    unique_ptr (T* ptr = nullptr) noexcept;      
    friend bool operator == (const unique_ptr& lhs, const unique_ptr& rhs);

/*** implementations inside the class after all declarations (I am not sure if this makes the code code any easier to understand)  ***/
  };

/**** Implementations outside the class ***/
/***  Convoluted things needed to make friend functions work ***/
/** like mentioned in : https://stackoverflow.com/questions/3989678/c-template-friend-operator-overloading  ***/

Some functions, like "Koenig operators", cannot be defined outside of the class itself:

friend bool operator == (const unique_ptr& lhs, const unique_ptr& rhs) {
  return lhs.get() == rhs.get();
}

this is a non-template friend of unique_ptr<T> , generated for each template instantiation of unique_ptr . There is no syntax in C++ that permits defining its body outside of unique_ptr . (You can create template friends which are defined outside, but not non-template friends whose arguments are dependent on the template arguments of the template class).

We can get around this by:

friend bool operator == (const unique_ptr& lhs, const unique_ptr& rhs) {
  return equal(lhs, rhs);
}

and then define equal as a template friend of unique_ptr .

But even there, you could do:

template <typename T>
class unique_ptr final {
  private:
    T* ptr_;
  public:
    unique_ptr (T* ptr = nullptr) noexcept {
      : ptr_{ ptr } {
    }

    friend bool operator == (const unique_ptr& lhs, const unique_ptr& rhs)
#include "unique_ptr_t_operator_equal_function_body.inc"
};

if you really wanted to split implementation and interface.

There are no technical barriers to separating implementation and interface into separate .h and .inc files, placing definitions inline in the template declaration, or placing the definition at the end of the .h file. Using multiple files has a tiny impact on compile times (as the filesystem or a cache of same usually has to be touched on a #include ), but that isn't usually large compared to other factors.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM