c++ - 在 C++ 中编写 structarray 映射仿函数的最清晰方法

标签 c++ readability functor pointer-to-member

这是一项针对最易读的做事方式的意见投票——是使用 C++ 指向成员的指针、字节偏移量,还是使用模板化仿函数来定义“从结构 foo 中选择成员 X”。

我有一个包含大量结构 vector 的类型,我正在编写一个实用函数,它基本上作为 reduce 运行。在其中的某些范围内。每个结构都将一组因变量与独立维度上的某个点相关联——发明一个简化的例子,假设它记录了一个房间随时间推移的一系列环境条件:

// all examples are psuedocode for brevity
struct TricorderReadings
{
  float time;  // independent variable

  float tempurature;
  float lightlevel;
  float windspeed; 
  // etc for about twenty other kinds of data...
}

我的函数只是执行一个 cubic interpolation猜测可用样本之间某个给定时间点的这些条件。

// performs Hermite interpolation between the four samples closest to given time
float TempuratureAtTime( float time, sorted_vector<TricorderReadings> &data)
{
    // assume all the proper bounds checking, etc. is in place
    int idx = FindClosestSampleBefore( time, data );
    return CubicInterp( time, 
                        data[idx-1].time, data[idx-1].tempurature,
                        data[idx+0].time, data[idx+0].tempurature,
                        data[idx+1].time, data[idx+1].tempurature,
                        data[idx+2].time, data[idx+2].tempurature );
}

我想概括这个函数,以便它可以一般地应用于任何成员,而不仅仅是温度。我可以想到三种方法来做到这一点,虽然它们都可以直接编写代码,但我不确定对于一年后必须使用它的人来说,哪种方法最易读。这是我正在考虑的:


指向成员的语法

typedef int TricorderReadings::* selector;
float ReadingAtTime( time, svec<TricorderReadings> &data, selector whichmember )
{
   int idx = FindClosestSampleBefore( time, data );
   return CubicInterp( time, data[idx-1].time, data[idx-1].*whichmember, 
                       /* ...etc */  );
}
// called like:
ReadingAtTime( 12.6f, data, &TricorderReadings::windspeed );

这感觉像是最“C++y”的实现方式,但它看起来很奇怪,而且整个指向成员的语法很少被使用,因此我团队中的大多数人都很难理解。这是技术上“正确”的方式,但也是我收到的最令人困惑的电子邮件方式。

结构偏移

float ReadingAtTime( time, svec<TricorderReadings> &data, int memberoffset )
{
   int idx = FindClosestSampleBefore( time, data );
   return CubicInterp( time, 
                       data[idx-1].time, 
                       *(float *) ( ((char *)(&data[idx-1]))+memberoffset ), 
                       /* ...etc */  );
}
// called like:
ReadingAtTime( 12.6f, data, offsetof(TricorderReadings, windspeed) );

这在功能上与上面的相同,但指针数学运算是明确的。我团队中的每个人(他们在 C++ 之前都学过 C)会立即熟悉和理解这种方法,而且它很健壮,但看起来很恶心。

模板化仿函数

template <class F>
float ReadingAtTime( time, svec<TricorderReadings> &data )
{
   int idx = FindClosestSampleBefore( time, data );
   return CubicInterp( time, 
                       data[idx-1].time, 
                       F::Get(data[idx-1]) ), 
                       /* ...etc */  );
}

// called with:
class WindSelector
{ 
   inline static float Get(const TricorderReadings &d) { return d.windspeed; }
}
ReadingAtTime<WindSelector>( 12.6f, data );

这是最直接和类似 STL 的做事方式,但它看起来像是一大堆额外的类型和语法以及即兴的类定义。它编译成与上面两个几乎完全相同的东西,但它还在整个可执行文件中转储了一堆冗余函数定义。 (我已经用 /FAcs 验证了这一点,但也许链接器再次将它们取出。)


以上三个都可以工作,编译器为它们生成几乎相同的代码;因此,我必须做出的最重要的选择就是最易读。你怎么看?

最佳答案

在这种情况下,我发现模板化仿函数非常清晰。

ReadingAtTime<WindSelector>( 12.6f, data );

关于c++ - 在 C++ 中编写 structarray 映射仿函数的最清晰方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1344840/

相关文章:

java - 多个返回语句,可读性

r - qgraph 可以在实际边缘之外渲染边缘标签吗?

c++ - 多映射中的 std::find_if 返回带有仿函数的错误

c++ - 如果 extern "C"包含与 Qt 库冲突怎么办?

c++ - 有没有办法用 googletest 创建自定义参数生成器?

c++ - 为什么不能在 C++ 模板参数中定义新类型?

coding-style - 为什么会有这么多缩进不良的代码?

c++ - 如何在 C++ 中创建自适应仿函数?

f# - map 函数的后置条件

c++ - 如何从参数化基函数生成多个函数指针?