链表值

时间:2016-06-14 06:54:53

标签: templates c++11

我有以下代码,我打算将它用于列表的总和或节点值。

#include <iostream>
#include <string>

using namespace std;

template <typename T, typename U, T node>
struct Sum {
    static const U sum = Sum<T,U,node->next>::sum + node->value;
};

template <typename T,typename U, NULL>
struct Sum {
    static const U sum = {};
};

template <typename T>
struct Node {
    T value;
    Node* next;
    Node() {
        value = {};
        next = NULL;
    }
};

int main()
{
    Node<string>* n1;
    n1->value = "Hello";
    Node<string>* n2;
    n2->value = "World!";
    n1->next = n2;

    const Node<string>* const nx=static_cast<const Node<string>* const>(n1);

    const string str=Sum<Node<string>*, string, nx>::sum;

    return 0;
}

我收到以下错误。

   1>templatemetaprogramming.cpp(15):
   error C2059: syntax error: 'constant'
   1>templatemetaprogramming.cpp(18):
   error C2976: 'Sum': too few template arguments 1> 
   1>templatemetaprogramming.cpp(16):
   note: see declaration of 'Sum'

我认为第一个是因为我不能将NULL用作Node的常量* 第二个似乎是相同的,我确实强制转换为一个常量的Node指针。任何人都可以帮忙解决它吗?谢谢

2 个答案:

答案 0 :(得分:1)

您尝试在编译时计算某些内容,该内容仅在运行时可用。实际上,这是链表的重点(它是一个动态数据结构,在运行程序之前是未知的)。因此,它的总和必须在编译时进行计算。

模板在编译时进行评估。因此,您只能将常量表达式传递给模板,但不能将表达式仅传递给运行时。

我很确定您在下面的代码中添加了所有conststatic_cast个关键字,因为编译器抱怨无法在该上下文中使用非const表达式或类似的东西:

const Node<string>* const nx=static_cast<const Node<string>* const>(n1);

const string str=Sum<Node<string>*, string, nx>::sum;

如果你看一下,从语义上说这没有任何意义。假设你最初写了这个(只是为了消除一些复杂性):

Node<string>* nx = new Node<string>(n1);

string str = Sum<Node<string>*, string, nx>::sum;

这将评估什么?让我们播放预处理器一段时间(当然编译器更聪明,但我不是): 第一个表达式将实例化以下类型的对象

struct Node {
    string* value;
    Node* next;
    Node() {
        value = {};
        next = NULL;
    }
};

第二行类似:

struct Sum {
    static const string sum = Sum<Node<string>*, string, nx->next>::sum + nx->value;
};

在这种情况下,nx是什么?这没有意义,对吧?同样,这不是编译器所做的,但你希望得到这个想法。

我编辑了你的代码来做你可能想要的事情。 (工作示例here

#include <iostream>
#include <string>

using namespace std;

template <typename T>
struct Node {
    T value;
    Node* next;
    Node() {
        value = T();
        next = NULL;
    }

    static T sum(Node<T> *node) {
        T s;

        Node<T> *next = node;

        while(next != NULL) {
            s = s + next->value;
            next = next->next;
        }

        return s;
    }
};

int main()
{
    Node<string> n1 = Node<string>();
    n1.value = string("Hello");
    Node<string> n2 = Node<string>();
    n2.value = string("World!");
    n1.next = &n2;

    string str = Node<string>::sum(&n1);
    cout << str << endl;

    return 0;
}

注意:

除了我上面提到的内容之外,您的代码还有许多其他问题。这例如

Node<string>* n1;
n1->value = "Hello";

将导致未定义的行为,并且最有可能出现分段错误,因为n1的内容未定义。我不知道你的c ++知识,但我认为在学习模板之前你应该学习指针,堆栈,堆等。

答案 1 :(得分:0)

您想要实现的是不可能的,您不能混合编译时计算和运行时执行:在您的情况下,链接列表是在运行时创建的。但是您的模板实例化是在编译时完成的:编译器无法预测必须创建多少模板才能运行完整列表。

您要做的事情必须使用标准功能,而不是模板。您只能将模板用于静态数据,例如类型,但最终不能用于运行时变量。运行时变量应作为函数参数传递。所以,你可以有这样的功能:

template <typename T, typename U>
U Sum(T *node)
{
     // run through complete list by iteration or recursion to do sum
}

您可以通过许多不同的设计实现您想要的效果。只需注意运行时数据作为函数参数传递。

如果要迭代静态数据,可以使用variadic模板。

在C ++ 11 std::string中始终是运行时数据,它不能用作常量表达式