Я использую учебное пособие по Arcsynthesis для изучения современного программирования трехмерной графики, и, хотя я понимаю большую его часть, я столкнулся с проблемой, которую автор называет «сложный код управления», я не могу понять, как работает этот код:
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},
};
Я не совсем понимаю, как указатель функции устанавливается внутри структуры в g_instanceList []. Я не понимаю синтаксически, как это работает, а затем, как этот g_instanceList используется в следующем сегменте:
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);
}
Я думал, что был довольно знаком с c ++ к этому моменту, но этот синтаксический сахар является новым для меня.
Заранее спасибо 🙂
Я не совсем понимаю, как указатель на функцию устанавливается внутри структуры в 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
Изменения длины массива, вам не нужно проходить всю кодовую базу, чтобы найти каждое использование длины массива. Кроме того, вы никогда не должны прямо указывать длину; вы можете сделать вывод об этом через агрегатную инициализацию.
Других решений пока нет …