从可变参数创建链接列表

问题描述

我想通过采用编译时给出的变量参数来创建链接列表 下面的说明:

我有一个如下所示的节点:

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_ptrstd::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;
}

https://godbolt.org/z/bbo5Tc