Является ли хорошей практикой не разделять объявления функций и определения для шаблонных классов? - PullRequest
0 голосов
/ 15 января 2019

Обычно в не шаблонных классах мы разделяем объявления и определения функций в отдельные файлы (.h и .cpp)

[1] Но вышеприведенная практика, похоже, не очень хорошо работает с шаблонными классами. Рекомендуется ли писать реализации в отдельном файле, а затем включать его в конец файла .h?

[2] Какая из приведенных ниже схем обычно рекомендуется для шаблонных классов?
[a] декларации и определения сразу или
[b] отдельные объявления и определения в одном файле

Учитывая сложный синтаксис, о котором нам нужно позаботиться, если мы пойдем по выбору [b]

Например. [А]

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();
    }
};

[Ь]

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 : /3913418/peregruzka-operatora-druga-v-shablone-c  ***/

1 Ответ

0 голосов
/ 15 января 2019

Некоторые функции, такие как «операторы Кенига», не могут быть определены вне самого класса:

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

это не шаблонный друг unique_ptr<T>, сгенерированный для каждого экземпляра шаблона unique_ptr. В C ++ нет синтаксиса, позволяющего определять его тело за пределами unique_ptr. (Вы можете создавать шаблонных друзей, которые определены снаружи, но не шаблонных друзей, аргументы которых зависят от аргументов шаблона класса шаблона).

Мы можем обойти это:

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

, а затем определите equal как друга шаблона unique_ptr.

Но даже там вы можете сделать:

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"
};

если вы действительно хотите разделить реализацию и интерфейс.

Не существует технических барьеров для разделения реализации и интерфейса на отдельные файлы .h и .inc, размещения определений в строке в объявлении шаблона или размещения определения в конце файла .h. Использование нескольких файлов оказывает незначительное влияние на время компиляции (поскольку файловая система или ее кэш обычно должны быть затронуты #include), но это обычно невелико по сравнению с другими факторами.

...