由于您没有指定 c++ 版本,我假设您使用的是最新的,现在是 C++17。最适合您现有代码的是使用if constexpr,我不会详细说明,因为还有其他好的答案。如果您卡在 C++14 或 C++11(或更糟糕的 03/98,在这种情况下您应该简单地升级),您将需要专门化您的模板。 (我会回到这个)
然而,这段代码违反了 CppCoreGuidelines 之一:ES.24: Use a unique_ptr<T> to hold pointers 通过编写模板来检测原始指针并删除它,总是需要分配。因此,您的链接列表不能引用现有事物的某些子数据。正如 cmets 中已经提到的,如果用户想要清理内存,请使用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; }
};
}
还有一种方法可以专门化单个方法,但是我不太熟悉,请参阅Stack overflow: Template specialization of a single method from a templated class 了解更多详细信息。