Ошибка шаблона в списке
Я пытаюсь реализовать Снежинку Коха. Ради практики я составил общий список, но у меня возникли некоторые проблемы.
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <gl/glut.h>
template <typename T> class Node {
public:
T data;
Node<T> *next;
Node<T>(T d) {
next = NULL;
data = d;
}
};
template <typename T> class List {
Node<T> *head;
int size;
public:
List() {
head = NULL;
size = 0;
}
void append(T data){
if(head == NULL) {
head = new Node<T>(data);
} else {
Node<T> *n = head;
while( n->next != NULL ) {
n = n->next;
}
n->next = new Node<T>(data);
}
size++;
}
void appendAll(List<T> data) {
if(data.getHead() == NULL)
return;
Node<T> *n = data.getHead();
append(n->data);
while(n->next != NULL){
append(n->next->data);
n = n->next;
}
}
Node<T>* getHead(){ return head; }
};
void myinit();
void display();
void draw_snowflake();
List<GLfloat[2]> divide_snowflake(GLfloat A[2], GLfloat B[2], int n);
GLfloat tri[3][2] = {{-1.0, -0.58}, {1.0, -0.58}, {0.0, 1.15}};
List<GLfloat[2]> snow;
int n;
int main(int argc, char **argv) {
n = 0;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500,500);
glutCreateWindow("Koch Snowflake");
glutDisplayFunc(display);
myinit();
glutMainLoop();
return EXIT_SUCCESS;
}
void myinit(){
// Initialize OpenGL
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glClearColor(1.0, 1.0, 1.0, 1.0);
glColor3f(0.0,0.0,0.0);
// Initialize list of line_loop
snow.append(tri[0]);
snow.append(tri[1]);
snow.append(tri[2]);
}
void display(){
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_LINE_LOOP);
draw_snowflake();
glEnd();
glFlush();
}
void draw_snowflake(){
List<GLfloat[2]> temp;
temp.append(snow.getHead()->data);
Node<GLfloat[2]> *curr = snow.getHead();
while(curr->next != NULL) {
temp.appendAll(divide_snowflake(curr->data, curr->next->data, n));
temp.append(curr->next->data);
curr = curr->next;
}
temp.appendAll(divide_snowflake(curr->data, snow.getHead()->data, n));
Node<GLfloat[2]> *ptr = temp.getHead();
printf("\n>Drawing %f, %f", ptr->data[0], ptr->data[1]);
glVertex2fv(ptr->data);
while(ptr->next != NULL) {
printf("\n>Drawing %f, %f", ptr->next->data[0], ptr->next->data[1]);
glVertex2fv(ptr->next->data);
ptr = ptr->next;
}
}
List<GLfloat[2]> divide_snowflake(GLfloat A[2], GLfloat B[2], int n) {
GLfloat A_Mid[2] = {A[0] + (B[0] - A[0]) / 3,
A[1] + (B[1] - A[1]) / 3};
GLfloat Mid[2] = {A[0] + (B[0] - A[0]) / 2,
A[1] + (B[1] - A[1]) / 2};
GLfloat B_Mid[2] = {B[0] - (B[0] - A[0]) / 3,
B[1] - (B[1] - A[1]) / 3};
GLfloat Peak[2] = {Mid[0] + (Mid[1] - B_Mid[1]) * sqrt(3.0),
Mid[1] + (Mid[0] - A_Mid[0]) * sqrt(3.0)};
List<GLfloat[2]> temp;
if(n > 0) temp.appendAll(divide_snowflake(A, A_Mid, n-1));
temp.append(A_Mid);
if(n > 0) temp.appendAll(divide_snowflake(A_Mid, Peak, n-1));
temp.append(Peak);
if(n > 0) temp.appendAll(divide_snowflake(Peak, B_Mid, n-1));
temp.append(B_Mid);
if(n > 0) temp.appendAll(divide_snowflake(B_Mid, B, n-1));
return temp;
}
Вот ошибка, которую я получаю:
Error 1 error C2440: '=' : cannot convert from 'GLfloat []' to 'float [2]' 13
Когда я только что инициализировал как список<GLfloat*
> он только установил бы данные узла как одно значение; в то время как я хочу очки. Для практических целей я хочу продолжать использовать общий список.
1 ответ
Давайте рассмотрим, каким был бы код, если бы вы использовали неуниверсальный список, а именно список, который работал с GLFloat[2]
s. Вот ваш код узла:
class Node {
public:
GLFloat[2] data;
Node *next;
Node(GLFloat[2] d) {
next = NULL;
data = d;
}
};
Важно отметить, что сейчас стоит отметить, что Node
конструктор на самом деле не принимает массив: он принимает GLFloat*
, Именно так C++ работает в этом отношении. (Странно для меня, это также, как это работает, когда вы позволяете типу аргумента зависеть от параметра шаблона: очевидно, массив тогда также рассматривается как указатель.)
Вы сейчас пытаетесь, делая data = d;
, чтобы назначить GLFloat*
к GLFloat[2]
, Это не имеет никакого значения: вы не можете просто взять указатель и поместить его значение в массив. Вы могли бы явно поставить d[0]
в data[0]
а также d[1]
в data[1]
, но это не будет очень общим, так как ваш список больше не будет работать с не-массивными типами.
Что можно сделать? Ну, одним из решений было бы специализировать ваш список для массивов. Код будет выглядеть примерно так...
template <typename T, std::size_t N>
class Node<T[N]> {
public:
T data;
Node<T> *next;
Node<T>(T d) {
next = NULL;
for (std::size_t i = 0; i < N; ++i)
data[i] = d[i];
}
};
Однако это может привести к значительному дублированию кода и к дальнейшим проблемам, таким как то, как вы можете возвращать элементы.
Мой совет будет использовать std::pair<GLFloat, GLFloat>
вместо. Это должно работать с вашим списком как есть. Кроме того, вы можете использовать std::array
если вы хотите хранить произвольное количество элементов.
И пока я все это комментирую: вы можете Node
шаблон класса в List
Шаблон класса, так как это деталь реализации. Вы также не должны определенно предоставлять getHead()
функция - не имеет смысла нарушать инкапсуляцию таким образом. Предоставить iterator
класс и пара begin()
а также end()
функции для итерации. Одна из возможных реализаций будет выглядеть следующим образом:
struct iterator {
friend List;
private:
Node* current;
iterator(Node* c) : current(c) {}
public:
iterator& operator++() {
current = current->next;
return *this;
}
friend bool operator==(iterator const& lhs, iterator const& rhs) {
return lhs.current == rhs.current;
}
T& operator*() {
return current->data;
}
T* operator->() {
return ¤t->data;
}
};
Это обеспечит достаточный интерфейс для всего, что вы уже сделали, и будет намного чище. Реализация более полного интерфейса, к сожалению, требует большого количества шаблонной информации; в этот момент вы можете перейти к простому std::list
,