用于访问作为参数传递的对象的不同成员的模板

发布于 2024-12-03 12:18:01 字数 882 浏览 2 评论 0原文

我有一个函数来计算在相邻点集上定义的不同变量的梯度。算法总是相同的,但根据计算的内容,访问邻居的不同成员数据,例如,在计算速度梯度时,使用Node::velocity,计算应力梯度时,使用Node::stress。避免多次编写相同函数的最佳方法是什么?

我想到了几种可能性:

  1. 传递 lambda 函数 (c++0x) 或返回相关特定成员数据的可调用对象,称为

    gradVelocity=computeGradient(listOfNeighbors,[](const Node& n){ return n.velocity; });
    

    减号是每次读取时的额外函数调用。

  2. 根据整数来模板化函数,说明正在计算的内容:

    enum{VAL_VELOCITY=0,VAL_STRESS,VAL_SOMETHING};
    模板 computeGradient(const std::list<节点>& 邻居){
        /*循环邻居*/
             value=(what==VAL_VELOCITY?neighbor.velocity:((what==VAL_STRESS)?neighbor.stress:neighbor.something);
        /* 等等 */
    }
    
    /* 这样调用 */
    gradVelocity=computeGradient(邻居);
    

    它也许应该是高效的(希望编译器能够在各个实例化中使用常量来优化条件),但可读性和可维护性相当低。

有更好的主意吗?

I have a function to compute gradient of different variable defined on set of neighbor points. The algorithm is always the same, but depending on what is computed, different member data of the neighbors are accessed, e.g. when computing gradient of velocity, use Node::velocity, when computing gradient of stress, use Node::stress. What is the best way to avoid writing the same function several times?

I had several possibilities in mind:

  1. Pass lambda function (c++0x)
    or callable object returning that particular member data in question, called like

    gradVelocity=computeGradient(listOfNeighbors,[](const Node& n){ return n.velocity; });
    

    The minus is extra function call at every read.

  2. Template the function based on integer saying what is being computed:

    enum{VAL_VELOCITY=0,VAL_STRESS,VAL_SOMETHING};
    template<int what> computeGradient(const std::list<Node>& neighbors){
        /*loop over neighbors*/
             value=(what==VAL_VELOCITY?neighbor.velocity:((what==VAL_STRESS)?neighbor.stress:neighbor.something);
        /* and so on */
    }
    
    /* called like this */
    gradVelocity=computeGradient<VAL_VELOCITY>(neighbors);
    

    It should be perhaps efficient (hoping compiler will optimize the conditional with constants away in individual instantiations), but readability and maintainability is pretty low.

Some better idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

|煩躁 2024-12-10 12:18:01

如果所有字段都具有相同的类型,则很容易使用指向成员的指针:

struct Node
{
  double stress;
  double velosity;
};

void foo(Node* pNode, double Node::*pValue)
{
  cout << pNode->*pValue << endl;
}

int main()
{
  Node n1 = { 1, 2 };

  foo(&n1, &Node::stress);
  foo(&n1, &Node::velosity);
}

更新:如果不是,则仍然很容易将指向成员的指针与模板结合起来:

struct Node
{
  double stress;
  double velosity;
  int dimension;
};

template<class T>
void foo(Node* pNode, T Node::*pValue)
{
  cout << pNode->*pValue << endl;
}

int main()
{
  Node n1 = { 1, 2 };

  foo(&n1, &Node::stress);
  foo(&n1, &Node::velosity);
  foo(&n1, &Node::dimension);
}

我认为这可能是最有效的方法方式。也是相当的形象生动。

If all of your fields have the same types, it's easy to use pointers to members:

struct Node
{
  double stress;
  double velosity;
};

void foo(Node* pNode, double Node::*pValue)
{
  cout << pNode->*pValue << endl;
}

int main()
{
  Node n1 = { 1, 2 };

  foo(&n1, &Node::stress);
  foo(&n1, &Node::velosity);
}

Update: If not, it's still easy to combine pointers to members with templates:

struct Node
{
  double stress;
  double velosity;
  int dimension;
};

template<class T>
void foo(Node* pNode, T Node::*pValue)
{
  cout << pNode->*pValue << endl;
}

int main()
{
  Node n1 = { 1, 2 };

  foo(&n1, &Node::stress);
  foo(&n1, &Node::velosity);
  foo(&n1, &Node::dimension);
}

I think this is probably the most efficient possible way. It's pretty vivid too.

李白 2024-12-10 12:18:01

指向成员的指针就是您所需要的。类型写为 TS::* T 是数据成员的类型,S 是结构或类。这是一个小例子:

#include <iostream>

struct Foo
{
  int a;
  double b;

  Foo(int a, double b)
    : a(a), b(b)
  { }
};

template<typename T, T Foo::* mem>
void print(const Foo& foo)
{
  std::cout << foo.*mem << std::endl;
}

int main()
{
  Foo f(5, 3.14);
  print<int, &Foo::a>(f);
  print<double, &Foo::b>(f);
}

Pointer to member is what you need. The type is written as T S::* T is the type of the data member, S is your struct or class. Here is a small example:

#include <iostream>

struct Foo
{
  int a;
  double b;

  Foo(int a, double b)
    : a(a), b(b)
  { }
};

template<typename T, T Foo::* mem>
void print(const Foo& foo)
{
  std::cout << foo.*mem << std::endl;
}

int main()
{
  Foo f(5, 3.14);
  print<int, &Foo::a>(f);
  print<double, &Foo::b>(f);
}
羅雙樹 2024-12-10 12:18:01

我是 Boost.Fusion 的忠实粉丝,更具体地说,是 Boost.Fusion.Map,它可以让你构建一个类型 ->值类型的地图。

struct Velocity {};
struct Stress {};

typedef boost::fusion::map<
  std::pair<Velocity, double>,
  std::pair<Stress, int>
> Map;

Map map;

现在,您可以使用 types 访问地图:

boost::fusion::at_key<Velocity>(map)

返回对 boost::fusion::result_of::at_key::type 类型变量的引用

通过适当的包装,您将获得:

extern Velocity const velocity;
extern Stress const stress;

myItem.access(stress) = 3;

当然,由于我们正在谈论模板,因此根本没有运行时损失:)

I am a huge fan of Boost.Fusion, and more specifically, the Boost.Fusion.Map, which let you build a type -> value kind of map.

struct Velocity {};
struct Stress {};

typedef boost::fusion::map<
  std::pair<Velocity, double>,
  std::pair<Stress, int>
> Map;

Map map;

Now, you can access the map with types:

boost::fusion::at_key<Velocity>(map)

returns a reference to a variable of type boost::fusion::result_of::at_key<Velocity, Map>::type

With appropriate wrapping, you get:

extern Velocity const velocity;
extern Stress const stress;

myItem.access(stress) = 3;

And of course, since we are talking templates, no runtime penalty, at all :)

沫尐诺 2024-12-10 12:18:01

Node 继承并使用虚拟访问怎么样?甚至可以使用 CRTP 来避免虚拟呼叫。

What about inheriting from Node and using virtual access? It would even be possible to use CRTP to avoid the virtual call.

草莓酥 2024-12-10 12:18:01

您可以将velocitystresssomething组合在一个数组中,并根据enum索引访问它们。

struct Node
{
  int attributes[3]; // contains 'velocity', 'stress', 'something';
  enum { VAL_VELOCITY=0, VAL_STRESS, VAL_SOMETHING };
};

用法:

Node n;
n.attributes[Node::VAL_VELOCITY] = <value>;  // writing 'Node::velocity'
<otherthing> = n.attributes[Node::VAL_SOMETHING]; // reading 'Node::something'

[注意:如果您想将属性保留在私有区域内,则在Node中提供getter和setter方法来访问它们。]

You can combine velocity, stress, something in a single array and access them based on enum index.

struct Node
{
  int attributes[3]; // contains 'velocity', 'stress', 'something';
  enum { VAL_VELOCITY=0, VAL_STRESS, VAL_SOMETHING };
};

Usage:

Node n;
n.attributes[Node::VAL_VELOCITY] = <value>;  // writing 'Node::velocity'
<otherthing> = n.attributes[Node::VAL_SOMETHING]; // reading 'Node::something'

[Note: If you want to keep attributes inside private region then provide getter and setter methods in Node for accessing them.]

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文