2012-07-10 42 views
0

我试图实施科赫的雪花。为了练习,我列了一个通用列表,但我遇到了一些问题。列表中的模板错误

#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*>这将只设置节点的数据作为单个值;而我想要点。出于实践目的,我想继续使用通用列表。

+2

为什么不使用'std :: list'?这是一个通用的列表,它的工作原理。 – mfontanini 2012-07-10 22:48:22

+0

@mfontanini:它说在最顶层的“练习”。如果每个程序员都默认从第1天开始图书馆的技术人员足够熟练,可以继续在将来编写图书馆? – 2012-07-10 22:49:08

+0

@EdS。哦,我总是想念:/。是的,我也创建了自己的结构。我只是以为他只是在创建一个列表,因为他想要一个“通用列表”。 – mfontanini 2012-07-10 22:49:46

回答

1

让我们考虑一下如果使用非通用列表的代码是什么:即与GLFloat[2]一起工作的列表。这是你的节点代码:

class Node { 
public: 
    GLFloat[2] data; 
    Node *next; 
    Node(GLFloat[2] d) { 
     next = NULL; 
     data = d; 
    } 
}; 

一个重要的考虑,现在要注意的是Node的构造实际上并没有采取一个数组:它需要一个GLFloat*。这就是C++在这方面的工作方式。 (奇怪的是我的,这也是它的工作方式,当你让参数类型依赖于一个模板参数:显然,一个array is also treated as a pointer然后)

您现在正在尝试,通过做data = d;,分配一个GLFloat*GLFloat[2]。这没有什么意义:你不能只取一个指针并把它的值放入一个数组中。您可以明确地将d[0]置入data[0]d[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 &current->data; 
    } 
}; 

这将为您到目前为止所做的一切足够的接口,并且将是更清洁。不幸的是,实现更完整的界面需要大量的样板;在那个时候,你可能希望切换到一个简单的std::list

+0

请注意'T&d'会起作用,导致'T = GLfloat [2]'。这是因为_arrays_没有价值语义(他们不能被_copied_)。 – 2012-07-11 00:26:07

+0

'T&d'将意味着'Node'构造函数将通过引用获取数组,但分配它仍然不起作用。 – 2012-07-11 00:39:36