在视频游戏中,资源以步进方式加载是很常见的,因此在单个线程中,加载栏可以在每个加载步骤更新。例如:
1 - >加载纹理A
2 - >将加载栏更新为2%
3 - >加载纹理B
4 - >将加载栏更新为4%
5 ...
这可以通过多种方式完成。其中之一是为每个加载步骤定义一个函数。
void LoadTextureA()
{
//Loading routine
...
}
这具有可读性的优点,不需要太多嵌套代码,甚至可能在某些情况下共享两个游戏状态之间的加载例程。
现在我想的是用模板概括这个“功能为步骤”的模型。让我们说。
template <int S>
struct Foo{
void LoadingStep()
{
}
};
template <>
struct Foo<0>
{
void LoadingStep()
{
//First loading step
...
}
};
如果我错了,请纠正我。但似乎我可以使用元编程将编译时间迭代到0到N步骤,并将这些专用函数分配给函数指针的数组或向量。 在编译时已知N个步骤及其各自的功能。 函数指针向量将按如下方式迭代:
template <int Steps>
class Loader {
public:
bool Load()
{
functionArray[m_step]();
if (++m_step == Steps)
return false; //End loading
else
return true;
}
private:
int m_step;
}
这可能吗?我知道这是更简单的方法。但除了项目要求,这是一个有趣的编程挑战
答案 0 :(得分:1)
我是基于类似问题的Kal回答实现的 Create N-element constexpr array in C++11
template <int S>
struct Foo{
static void LoadingStep()
{
}
};
template <>
struct Foo<0>
{
static void LoadingStep()
{
//First loading step
}
};
template<template<int S> class T,int N, int... Rest>
struct Array_impl {
static constexpr auto& value = Array_impl<T,N - 1, N, Rest...>::value;
};
template<template<int S> class T,int... Rest>
struct Array_impl<T,0, Rest...> {
static constexpr std::array<void*,sizeof...(Rest)+1> value = {reinterpret_cast<void*>(T<0>::LoadingStep),reinterpret_cast<void*>(T<Rest>::LoadingStep)...};
};
template<template<int S> class T,int... Rest>
constexpr std::array<void*,sizeof...(Rest)+1> Array_impl<T,0, Rest...>::value;
template<template<int S> class T,int N>
struct F_Array {
static_assert(N >= 0, "N must be at least 0");
static constexpr auto& value = Array_impl<T,N>::value;
F_Array() = delete;
F_Array(const F_Array&) = delete;
F_Array(F_Array&&) = delete;
};
使用示例:
int main()
{
auto& value = F_Array< Foo ,4>::value;
std::cout << value[0] << std::endl;
}
这产生了void *指向模板函数的指针数组:
Foo<0>::LoadinStep()
Foo<1>::LoadinStep()
Foo<2>::LoadinStep()
Foo<3>::LoadinStep()
Foo<4>::LoadinStep()
因为Foo&lt; 1..3&gt;不专业,他们将落入Default LoadingStep函数
答案 1 :(得分:0)
是。这是可能的。如果使用模板元编程,则不需要使用运行时循环,而是递归调用模板方法:
#include <iostream>
// The template numerated methods
template <int S> struct Foo{static void LoadingStep(){}};
template <> struct Foo<0> {static void LoadingStep(){std::cout<<0;}};
template <> struct Foo<1> {static void LoadingStep(){std::cout<<1;}};
template <> struct Foo<2> {static void LoadingStep(){std::cout<<2;}};
// The loader template method
template <int Step>
void Loader()
{
Foo<Step>::LoadingStep();
Loader<Step-1>();
}
// Stopping rule
template <> void Loader<-1>(){}
int main()
{
Loader<2>();
}
答案 2 :(得分:0)
如果你想要一个数组:
LoadingFunction functionArray[] = {Function0, Function1, Function2};
.....
for (int i = 0; i < nSteps; ++i)
RunStep(i, nSteps, Function[i]);
或用它初始化一个std容器。
如果你想要模板,你可以写
for (int i = 0; i < nSteps; ++i)
RunStep(i, nSteps, Function<i>);
i
中的Function<i>
必须是常量。所以你必须用模板递归的东西来做:
template <int i, int NSteps> struct RunSteps
{
void Run()
{
RunStep(i, NSteps, Function<i>);
RunSteps<i+1, NSteps>::Run();
}
};
template <int NSteps> struct RunSteps<NSteps, NSteps>
{
void Run() {}
};
RunSteps<0, NSteps>::Run();
编译时迭代并不存在。 for循环和模板递归的东西完全相同。编译器能够展开循环,就像内联调用一样。
看起来很少有人能够通过模板化这些东西获得很多东西,而且还有很多东西要输掉。
目前尚不清楚为什么要在编译时将模板化函数放入数组中,但是现在就去了:
LoadingFunction functionArray[] = {Function<0>, Function<1>, Function<2>};
现在,如果你不想像这样手动枚举函数,那可能会有点挑战。对于旧版C数组或任何std容器,似乎都不可能。假设你确实需要它,可以编写一个能够进行初始化的自定义容器。
template <template <int> class FunctionWrappper, int NFunctions>
class MyOptimizedFunctionArray {
// filling this space is left as an exercise
};