2

I am using arcsynthesis' tutorial to learn modern 3D graphics programming, and while I am understanding most of it I have run into a snag with what the author calls "complex management code" I can't understand how this code works:

struct Instance
{
    typedef glm::vec3(*OffsetFunc)(float);

    OffsetFunc CalcOffset;

    glm::mat4 ConstructMatrix(float fElapsedTime)
    {
        glm::mat4 theMat(1.0f);

        theMat[3] = glm::vec4(CalcOffset(fElapsedTime), 1.0f);

        return theMat;
    }
};


Instance g_instanceList[] =
{
    {StationaryOffset},
    {OvalOffset},
    {BottomCircleOffset},
};

I don't quite get how the function pointer is getting set inside the struct in the g_instanceList[] I don't get syntactically how this works and then how this g_instanceList is used in the next segment here:

float fElapsedTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
    for(int iLoop = 0; iLoop < ARRAY_COUNT(g_instanceList); iLoop++)
    {
        Instance &currInst = g_instanceList[iLoop];
        const glm::mat4 &transformMatrix =
currInst.ConstructMatrix(fElapsedTime);

        glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE,     glm::value_ptr(transformMatrix));
    glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
}

I thought I was pretty familiar with c++ by this point but this syntactic sugar is new to me. Thanks in advance :)

4

1 回答 1

2

我不太明白函数指针是如何在 g_instanceList[] 的结构中设置的

Instance一个聚合类型。它可能有一个成员函数,但这并不意味着它不是一个聚合。在 C++98/03 中,可以使用聚合初始化来初始化聚合类型的对象:

struct Aggregate
{
  int x;
  int y;
};

Aggregate agg = { 5, 4 };
assert(4 == agg.y); //Will be true.

结构中的每个成员都使用每个单独的值进行初始化,按照这些成员在结构中声明的顺序。5进入x,4进入y

Instance是一个聚合体。它只有一个成员。该成员恰好是函数指针类型,但 C++ 不在乎;它是一个值,可用于聚合初始化。

C++ 数组也是一个聚合。所以你可以用聚合初始化来初始化一个数组:

int arr[4] = {3, 45, 9, 81};

C++ 还允许您使用聚合初始化来初始化数组,其中数组的大小由初始化程序确定:

int arr[] = {5, 2};
//arr will have 2 elements.

因此,g_instanceList是一个数组,因此是一个受聚合初始化的聚合。它的大小将由聚合初始化语法提供的值的数量决定。数组的每个元素也是一个聚合,因此数组的每个元素都可以被聚合初始化。

Instance g_instanceList[] =
{
    {StationaryOffset},
    {OvalOffset},
    {BottomCircleOffset},
};

聚合初始化列表的每个成员本身就是一个聚合初始化,它初始化一个Instance对象。StationaryOffset其余的是与成员的签名匹配的函数指针Instance。就这样Instance::CalcOffset被填满了。


这个 g_instanceList 如何在这里的下一段中使用

如何使用它是非常常见的 C++。第一行获取对其中一个Instance数组元素的引用。这样做只是为了使代码更短;它不必g_instanceList[iLoop]每次都使用来谈论Instance它正在使用的内容。第二行调用Instance(它本身调用内部函数指针)的成员函数,将结果存储在一个变量中。

如果您在谈论ARRAY_COUNT,那只是一个方便的宏来获取...好吧,数组元素的计数。C++ 编译器知道有多大g_instanceList,所以宏用于让编译器自己计算它。这样,如果g_instanceList数组长度发生变化,您不必遍历整个代码库来查找数组长度的每次使用。此外,您不必直接说明长度;您可以通过聚合初始化来推断它。

于 2013-08-08T04:57:34.447 回答