我有以下代码,我打算将它用于列表的总和或节点值。
#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指针。任何人都可以帮忙解决它吗?谢谢
答案 0 :(得分:1)
您尝试在编译时计算某些内容,该内容仅在运行时可用。实际上,这是链表的重点(它是一个动态数据结构,在运行程序之前是未知的)。因此,它的总和必须在编译时进行计算。
模板在编译时进行评估。因此,您只能将常量表达式传递给模板,但不能将表达式仅传递给运行时。
我很确定您在下面的代码中添加了所有const
和static_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
中始终是运行时数据,它不能用作常量表达式