问题描述
我想通过采用编译时给出的变量参数来创建链接列表 下面的说明:
template<typename T>
struct Node
{
Node(const T& data,Node* next = nullptr ) : m_data(data),m_next(next)
{}
T m_data;
Node *m_next;
};
我有一个函数,该函数接受如下所示的可变数量的参数(可变),并且应该能够从所有参数创建链接列表,并返回所创建列表的头*(起始指针)
template <class ... Ts>
constexpr Node* create(Ts && ... ts) {
// should be able to create all nodes and return Head* for the given created list
//return Head
}
主要功能如下:
int main()
{
auto *k = create(1,2,3,4,5,6);
auto *n = create(); // should handle no arguments case
auto *l = create(9,10,11,22,4567,90);
return 0;
}
解决方法
这里是完整的测试程序。 create
例程使用标准的尾部递归和一些可变参数模板魔术。这使用C ++ 17的if constexpr
,对于C ++ 14,您必须将create
专门化为空参数列表(return nullptr;
)。
Marek的answer还包含关于unique_ptr
和std::initializer_list
的有效点。
#include <iostream>
struct Node_t {
Node_t(int v = 0,Node_t* n = nullptr): value(v),next(n) {}
int value;
Node_t* next;
};
constexpr Node_t* create() {
return nullptr;
}
template <class Head,class... Tail>
constexpr Node_t* create(Head const& head,Tail const&... tail) {
Node_t* result = new Node_t(head);
if constexpr(sizeof...(tail) > 0) {
result->next = create(tail...);
}
return result;
}
void printList(Node_t* n) {
if (!n)
return;
std::cout << n->value;
if (n->next) {
std::cout << ",";
printList(n->next);
}
}
int main() {
Node_t* l = create(1,2,3);
std::cout<< "List: "; printList(l);
std::cout << std::endl;
Node_t* l2 = create();
std::cout<< "EmptyList: "; printList(l2);
}
,
请不要过于复杂,只需使用std::initializer_list。在这里使用可变参数是过大的选择。
另外Node
应该是列表的实现细节。因此,创建模板类List
,它将是唯一使用Node
的模板。
template<typename T>
struct Node
{
T m_data;
Node *m_next;
};
template<typename T>
class List
{
public:
List(std::initializer_list<T> ini)
{
for (const T& x : ini) {
push_back(x);
}
}
void push_back(const T& x);
....
private:
std::unique_ptr<Node> m_front;
Node* m_back;
};
这是不好的方法,面试的任务很差,但这是:
template<typename T>
struct Node
{
constexpr explicit Node(const T& x) : m_data{x}
{}
T m_data;
std::unique_ptr<Node> m_next;
};
template<typename T>
using Node_t = Node<std::remove_reference_t<T>>;
template<typename T>
using NodePtr = std::unique_ptr<Node_t<T>>;
template<typename T>
constexpr NodePtr<T> create(T&& x)
{
return std::make_unique<Node_t<T>>(std::forward<T>(x));
}
template <typename T1,typename ... Ts>
constexpr NodePtr<T1>
create(T1&& x1,Ts && ...xi)
{
auto r = create(std::forward<T1>(x1));
r->m_next = create(std::forward<Ts>(xi)...);
return r;
}