c++ - 如何在不支持的 C++ 方言中最好地实现函数指针?

标签 c++

例如,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/

相关文章:

c++ - vector 中的 vector 在第二维生成重复值

c++ - 解析字符串并替换

c++ - CSocket Server 获取客户端IP地址

c++ - 加载共享库时出错 : libboost_system. 所以 1.49.0: 没有这样的文件或目录

c++ - 二进制通过http

c++ - 使用抽象返回类型设计继承

C++ 非静态数据成员初始化器,只是有点困惑

c++ - 是否有编译时函数/宏来确定 C++0x 结构是否为 POD?

python - 可以使用 while(file >> ...) C++ 习惯用法来读取 Cython 中的文件吗?

c++ - 从管道读取时的随机字符