例如,OpenCL 不支持函数指针。一些针对嵌入式硬件的工具链也没有。 RPC 需要一个与跨不相交堆工作的函数指针等效的东西。因此,希望有足够的现有技术来提供一个已知的(尽管对我来说还不是)好的解决方案。
我已将这个问题标记为“C++”,尽管我知道一种看起来像 C++ 但没有函数指针的语言实际上不是 C++。这仍然是最接近的。我有可用的模板等,只是运行时支持不多。
例如,可能要求程序员为他们想要通过指针传递的每个函数分配一个枚举,并编写一个对每个函数发出直接调用的开关。另外,传递该枚举的元素,而不是函数的地址,并使用 union 执行某些操作来处理参数的变化。或者,可以对函数的符号名称进行散列(半自动分配值)并根据这些散列编写一个开关。这就是我今天正在做的事情,但是我想消除自定义编译器支持。
手动写出任一开关,并在需要时添加条目,这并不是很好。因此,也许可以通过在全局数组上展开循环来构建 if/else 链。
这里没有类型安全,所以也许每个函数类型应该是单独的哈希/枚举/数组/其他。这将删除一些 union 。
经过几个月的断断续续的思考,我还没有看到一个干净/可维护的解决方案(这不是定制的编译器 channel )。欢迎提出想法。
最佳答案
您在使用开关方面走在正确的道路上。
早在 1999 年至 2001 年,我是一个项目的主要开发人员,该项目自 nearly vanished from the web ,在 Apple 的 Quicktime 中进行实时立体 3D 渲染。
它提供了一种自定义电影格式,采用标准 2D 视频,将其与 256 级深度轨道相结合并渲染每一帧。
播放提供了输出选择:
- 不同种类的彩色镜片:青色-红色、红-绿色等,这在新奇事物中经常出现,其中 3D 是通过遮蔽偏移实现的
- 单色的不同颜色镜片,其中颜色仅用于提供深度效果 - 对于精细的科学和采矿数据非常有用,例如观察岩石
- 同步快门 LCD 眼镜,以 60Hz 运行,内联插入 120Hz CRT,以及
- 非常早期的裸眼显示器(每台约 10 万美元,用于 session )。
它在 Windows 和那个时代的经典 Mac 设备上运行,以 24fps 进行实时渲染。对于 G3 这样的硬件来说并不容易 iMac 350MHz PowerPC。
它还能够调整每帧的深度渲染效果。您可以选择让影片出现在屏幕的前面或后面,并调整深度幅度以适应物体看起来的距离。
因此,结合不同的电影格式,需要切换的很多内容可能会不断变化。
我认为这是我编程生涯的顶峰。这是一个有趣且极具挑战性的项目,研究如何在 Quicktime 中提供这种 3D 渲染,并且在获得性能方面也具有技术挑战性。在 2000 年的 WWDC 上,Apple QuickTime 工程师对我们的成功表示祝贺并感到惊讶。这一切都是使用标准 QuickTime API 完成的,并且运行非常稳健,不涉及黑客攻击。
下面的大代码示例展示了我如何使用模板和开关。嵌套的 switch 语句分解了上面讨论的每帧变量。
嵌套开关每渲染一帧运行一次。它们会导致调用一个独特的函数,该函数循环渲染每个像素 - 我认为模板会生成大约 700 种不同的变体。
我记得 CodeWarrior 编译器的重大升级是在该项目的中途进行的,它优化了模板化函数。我们的编译时间增加了 4 倍,但生成的代码更小、速度更快。
// from rendererersP.h
/**
this template definition provides the implementation of the
stereo pair algorithm for the argument class types.
pass a single StereoRenderPars struct which tells the function
about the source and destination data.
*/
template<class ImageFormat,
class DepthFormat,
class GlassFormat,
class DestinationFormat>
void RenderStereoPair (StereoRenderPars *rp)
{
// from render_switch.cpp
// the entry point for stereo
int
renderStereo(GlassType gt, ImageFormat sf, StereoRenderPars *rp, bool outputGrey)
{
int status = 0;
switch (gt) // The GT Stringers!
{
case gtRLeftBGRight :
{
switch (outputGrey)
{
case true :
{
switch (sf)
{
case ifRGB :
RenderStereoPair<ImageGrayRGB, DepthUnsigned24, GlassRLeftBGRight, ImageGrayRGB>(rp);
break;
case ifBGR :
RenderStereoPair<ImageGrayBGR, DepthUnsigned24, GlassRLeftBGRight, ImageGrayBGR>(rp);
break;
case ifARGB :
RenderStereoPair<ImageGrayARGB, DepthUnsigned32, GlassRLeftBGRight, ImageGrayARGB>(rp);
break;
case ifBGRA :
RenderStereoPair<ImageGrayBGRA, DepthUnsigned32, GlassRLeftBGRight, ImageGrayBGRA>(rp);
break;
case if555RGB :
RenderStereoPair<ImageGray555RGB, DepthUnsigned16, GlassRLeftBGRight, ImageGray555RGB>(rp);
break;
case if565RGB :
RenderStereoPair<ImageGray565RGB, DepthUnsigned16, GlassRLeftBGRight, ImageGray565RGB>(rp);
break;
default :
status = 1;
}
}
break;
case false :
{
switch (sf)
{
case ifRGB :
RenderStereoPair<ImageRGB, DepthUnsigned24, GlassRLeftBGRight, ImageRGB>(rp);
break;
case ifBGR :
RenderStereoPair<ImageBGR, DepthUnsigned24, GlassRLeftBGRight, ImageBGR>(rp);
break;
case ifARGB :
RenderStereoPair<ImageARGB, DepthUnsigned32, GlassRLeftBGRight, ImageARGB>(rp);
break;
case ifBGRA :
RenderStereoPair<ImageBGRA, DepthUnsigned32, GlassRLeftBGRight, ImageBGRA>(rp);
break;
case if555RGB :
RenderStereoPair<Image555RGB, DepthUnsigned16, GlassRLeftBGRight, Image555RGB>(rp);
break;
case if565RGB :
RenderStereoPair<Image565RGB, DepthUnsigned16, GlassRLeftBGRight, Image565RGB>(rp);
break;
default :
status = 1;
}
}
}
}
break;
case gtBGLeftRRight :
{
switch (outputGrey)
{
case true :
{
switch (sf)
{
case ifRGB :
RenderStereoPair<ImageGrayRGB, DepthUnsigned24, GlassBGLeftRRight, ImageGrayRGB>(rp);
break;
case ifBGR :
RenderStereoPair<ImageGrayBGR, DepthUnsigned24, GlassBGLeftRRight, ImageGrayBGR>(rp);
break;
case ifARGB :
RenderStereoPair<ImageGrayARGB, DepthUnsigned32, GlassBGLeftRRight, ImageGrayARGB>(rp);
break;
case ifBGRA :
RenderStereoPair<ImageGrayBGRA, DepthUnsigned32, GlassBGLeftRRight, ImageGrayBGRA>(rp);
break;
case if555RGB :
RenderStereoPair<ImageGray555RGB, DepthUnsigned16, GlassBGLeftRRight, ImageGray555RGB>(rp);
break;
case if565RGB :
RenderStereoPair<ImageGray565RGB, DepthUnsigned16, GlassBGLeftRRight, ImageGray565RGB>(rp);
break;
default :
status = 1;
}
}
break;
case false :
{
switch (sf)
{
case ifRGB :
RenderStereoPair<ImageRGB, DepthUnsigned24, GlassBGLeftRRight, ImageRGB>(rp);
break;
case ifBGR :
RenderStereoPair<ImageBGR, DepthUnsigned24, GlassBGLeftRRight, ImageBGR>(rp);
break;
case ifARGB :
RenderStereoPair<ImageARGB, DepthUnsigned32, GlassBGLeftRRight, ImageARGB>(rp);
break;
case ifBGRA :
RenderStereoPair<ImageBGRA, DepthUnsigned32, GlassBGLeftRRight, ImageBGRA>(rp);
break;
case if555RGB :
RenderStereoPair<Image555RGB, DepthUnsigned16, GlassBGLeftRRight, Image555RGB>(rp);
break;
case if565RGB :
RenderStereoPair<Image565RGB, DepthUnsigned16, GlassBGLeftRRight, Image565RGB>(rp);
break;
default :
status = 1;
}
}
}
}
break;
关于c++ - 如何在不支持的 C++ 方言中最好地实现函数指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59870562/