Поскольку вы не указали версию c ++, я предполагаю, что вы используете самую последнюю версию, которая сейчас называется C ++ 17. Наиболее подходящим вариантом для вашего существующего кода является использование if constexpr
, я не буду останавливаться на этом, поскольку есть и другие хорошие ответы на этот вопрос. Если вы застряли на C ++ 14 или C ++ 11 (или хуже 03/98, в этом случае вам следует просто обновить), вам нужно будет специализировать свой шаблон. (Я вернусь к этому)
Этот код, однако, нарушает одно из CppCoreGuidelines: ES.24: Use a unique_ptr<T> to hold pointers
При написании вашего шаблона для обнаружения необработанных указателей и удаления его, всегда есть выделить. Следовательно, ваш связанный список не может ссылаться на некоторые субданные чего-то существующего. Как уже упоминалось в комментариях, если пользователи хотят очистить память, используйте std::unique_ptr
. Пример:
namespace Linked{
template <class T>
struct Nodo{
T Element;
Nodo<T> *Next{nullptr};
Nodo() = default;
~Nodo() = default;
};
}
// Has ownership
auto node = Nodo<std::unique_ptr<int>>{};
node.element = std::make_unique<int>(42);
// Has ownership (to array of 42 elements)
auto node = Nodo<std::unique_ptr<int[]>>{};
node.element = std::make_unique<int[]>(42);
// No ownership
int value = 42;
auto node = Nodo<int>{};
node.element = &value;
При этом право собственности становится для звонящего абонентом и прозрачным для вас. (поскольку вам не нужно знать об этих массивах, об этом знает std :: unique_ptr). Возможно, вы захотите наложить некоторые ограничения на T, например, добавив static_assert(std::is_nothrow_move_constructable<T>);
.
. Это решение выше решает проблему в C ++ 11 и выше и должен быть рекомендованным подходом.
Если нет, используйте if constexpr
, если ваше условие не может быть записано в выделенном классе в C ++ 17. И частичная специализация на C ++ 14 и C ++ 11.
namespace Linked{
template <class T>
struct Nodo{
T Element;
Nodo<T> *Next{nullptr};
Nodo() = default;
~Nodo() = default;
};
template <class T>
struct Nodo<T*>{
T *Element{nullptr};
Nodo<T> *Next{nullptr};
Nodo() = default;
~Nodo() { delete Element; }
};
}
Если вы не хотите слишком много повторять свой код
namespace Linked{
template <class T, class Me>
struct AbstractNodo{
T Element;
Me *Next{nullptr};
// All common code
};
template <class T>
struct Nodo : AbstractNodo<T, Nodo<T>>{
Nodo() = default;
~Nodo() = default;
};
template <class T>
struct Nodo<T*> : AbstractNodo<T, Nodo<T*>>{
Nodo() = default;
~Nodo() { delete Element; }
};
}
Существует также способ Я специализируюсь на одном методе, однако я не очень знаком с ним, см. Переполнение стека: специализация шаблона для одного метода из шаблонного класса для получения более подробной информации.