2012-07-10 24 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