【问题标题】:Template error in list列表中的模板错误
【发布时间】:2012-07-10 22:46:08
【问题描述】:

我正在尝试实现 Koch 的雪花。为了练习起见,我制作了一个通用列表,但我遇到了一些问题。

#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

当我刚刚初始化为 List&lt;GLfloat*> 时,它只会将节点的数据设置为单个值;然而,我想要积分。出于练习目的,我想继续使用通用列表。

【问题讨论】:

  • 你为什么不用std::list?这是一个通用列表,并且有效。
  • @mfontanini:上面写着“练习”。如果每个程序员从第一天起就默认使用库,那么谁会有足够的技能在未来继续编写库?
  • @EdS。哦,我总是想念那个:/。是的,我也创建了自己的结构。我只是认为他创建一个列表只是因为他想要一个“通用列表”。
  • 不过,分开编写列表和科赫雪花会更有意义,然后至少在列表没有错误后将它们放在一起。就目前而言,超过一半的代码是无关紧要的。

标签: c++ templates opengl type-conversion class-template


【解决方案1】:

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

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] 放入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&lt;GLFloat, GLFloat&gt;。这应该适用于您的列表。或者,如果你想存储任意数量的元素,你可以使用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

【讨论】:

  • 请注意,T&amp; d 会起作用,从而导致T = GLfloat[2]。这是因为 数组 没有值语义(它们不能被复制)。
  • T&amp; d 意味着Node 构造函数将通过引用获取一个数组,但分配它仍然不起作用。
猜你喜欢
  • 1970-01-01
  • 2017-05-05
  • 1970-01-01
  • 2010-11-12
  • 2014-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多