Предотвращение проблемы переопределения в случае разделения объявления и определения шаблонного класса

#c #templates #one-definition-rule

#c #шаблоны #одно определение-правило

Вопрос:

Вопрос в том, что в случае создания шаблона из класса с помощью шаблонов, затем включите его для использования как обычно: будет получена ошибка, описанная ниже:

Если требуется использовать struct что-либо прямолинейно в Node.inl. Он должен включать заголовок «Node.h» следующим образом, но это приведет к некоторым проблемам. Мы нарушаем правило одного определения, но шаблонный класс должен включать свои определения в тот же файл, в котором они объявлены. В противном случае компилятор забудет указать функции-члены при создании экземпляра. В результате мы не можем использовать эти функции через инициализированный экземпляр. Итак, как мы можем управлять этим, хотя мы хотим сохранить разделенность объявлений и определений, сохраняем, не нарушая одно правило определения?

Node.inl:

 #include "Node.h"

void foo(){
    struct Something s{1, 2};
}

template <class T>
Node<T>::Node(int data, Node<T> *next) : m_data{data}, m_next{next} {}

template <class T>
void Node<T>::setData(int data) {
    m_data = data;
}

template <class T>
int Node<T>::getData() const {
    return m_data;
}

template <class T>
void Node<T>::setNext(Node<T> *next) {
    m_next = next;
}

template <class T>
Node<T> * Node<T>::getNext() const {
    return m_next;
}

template <class T>
void Node<T>::allocMemoryNext() {
    m_next = new Node<T>();
}
  

Node.h:

 #ifndef THE1_NODE_H
#define THE1_NODE_H

struct Something{
    int x;
    int y;
};

template <class T>
class Node {
private:
    T m_data;
    Node *m_next;

public:
    explicit Node(int data = 0, Node *next = nullptr);

    void setData(int data);

    [[nodiscard]] int getData() const;

    void setNext(Node *next);

    [[nodiscard]] Node *getNext() const;

    void allocMemoryNext();
};

#include "Node.inl"

#endif //THE1_NODE_H

  

Ответ №1:

мы хотим сохранить разделенность объявлений и определений

В том, что касается шаблонов, такой «разделенности» нет. Для того, чтобы кто-либо мог их использовать, они должны быть определены. И Node.h предоставляет эти определения.

Node.inl является частью Node.h. Вы логически разделили текст на разные файлы, но они не являются отдельными, насколько это касается какой-либо практической реальности. Каждый пользователь Node.h также должен получать материал Node.inl, поэтому вы #include "Node.inl" в конце файла. Никто, кроме Node.h, не должен включать Node.inl, поэтому нет причин для Node.inl #include "Node.h" .

Таким образом, проблем нет, как только вы удалите ненужное включение вещи, которая определенно уже существует.

Комментарии:

1. Но я могу захотеть использовать структуру, которая определена в «Node.h» в «Node.inl», поэтому мне нужно включить. На самом деле, это то, о чем спрашивают.

2. @ibrahimkoz: Нет, вам не нужно включать ничего подобного. Файлы в C не являются отдельной, заблокированной конструкцией. #include sion — это просто копирование / вставка текста из одного файла в другой. Node.inl включен после множества определений в Node.h, поэтому у него есть к ним доступ.

3. Нет, вы ошибаетесь, классы и структуры должны быть включены для использования на месте.

4. @ibrahimkoz: Их не нужно «включать»; они должны быть видимыми . И они видны. Удалите #include "Node.h" из вашего Node.inl файла, и вы обнаружите, что он может видеть Something просто отлично. При условии, что Node.h это единственный файл, который включает Node.inl .

5. Нет, в этом случае вы не можете получить доступ к элементам чего-либо. Таким образом, вы ничего не можете сделать, пока можете это видеть.