如何在C ++中实现公式模式?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在C ++中实现公式模式?相关的知识,希望对你有一定的参考价值。

Disclaimer

首先,我很抱歉这个问题的标题。对我来说,简单地制定我想要的东西并不容易。如果你知道如何改变它 - 请,建议。

Problem description

预赛

我有大量的结构化数据,它是不同类型变量的树(ROOT TTree对象)。该数据的基本单位是所谓的进入或事件。因此,不同的条目包含相同变量的不同值。后者不是最明确的陈述。以下列方式考虑该树:它就像一个矩阵,其中行是条目号(0,1,2,...),列是变量名(能量,动量,θ,......)。

我们需要的

我们需要对这些事件进行全局选择。即我们必须决定哪些事件用于进一步分析,哪些事件不是。为了达到这个目的,我们开发了几种算法,我们称之为选择器。这些选择器使用事件的不同参数(变量)来决定它是否通过。当前选择器背后的过程或算法我们将调用此算法在其中使用的公式和变量 - 变量。

我们正按活动进行选拔活动。即每个事件都经过每个选择器,如果它们中的一些(选择器)失败(未通过),则下一个事件转向。

编程问题

每个选择器由从抽象基类派生的类表示:

 class Selector:
 {
     protected :
         bool status;

     public :
         virtual bool Formula() = 0;//must be overridden for a specific Selector
 };

你看到纯函数Formula没有参数。这是合理的,因为在我们知道我们使用什么选择器之前,我们不知道它应该采用什么参数。因此,变量信息可以存储在类数据成员中。例如,就这样

class SpecificSelector : public Selector
{
    private :
        std::vector<?> variables;//or std::array

    public :
        void AddVariable ( /*pointer to a variable*/ ) { variables.push_back( &variable ); }
        bool Formula() { return ( *variables[0] + *variables[1] ) > 1 ? true : false; }
};

可是等等。变量可以是任何(合理的)类型。所以我们必须知道什么是什么。可能是吧

class SpecificSelector : public Selector
{
    private :
        std::vector<int* > intVariables;//or std::array
        std::vector<float* > floatVariables;
    public :
        void AddIntVariable ( /*pointer to a variable*/ ) { intVariables.push_back( &variable ); }
        void AddFloatVariable ( /*pointer to a variable*/ ) { floatVariables.push_back( &variable ); }
        bool Formula() { return ( *intVariables[0] + *intVariables[1] ) > 1 ? true : false; }
};

但类型可能更具异国情调。例如,数组。

也许这里是模板的地方?什么是达到预期的方式?如何实现这种Formula成员函数。

尽管我们以这种特定方式提出问题,但我们认为问题非常普遍。

答案

如果你想在事件循环之外定义你的剪切,你可以做这样的事情。我假设你至少使用c++11root6已经要求它多年了。

#include <iostream>
#include <type_traits>
#include <tuple>
#include <vector>

// Function that checks if calls to all tuple elements are true
template <typename T, size_t I = 0>
std::enable_if_t<(I+1 < std::tuple_size<T>::value),bool>
apply_cuts(T& cuts) { // base case
  if (!std::get<I>(cuts)()) return false;
  return apply_cuts<T,I+1>(cuts);
}
template <typename T, size_t I = 0>
std::enable_if_t<(I+1 == std::tuple_size<T>::value),bool>
apply_cuts(T& cuts) { // last cut
  return std::get<I>(cuts)();
}
template <typename T, size_t I = 0>
std::enable_if_t<(std::tuple_size<T>::value == 0),bool>
apply_cuts(T&) { // no cuts
  return true;
}

int main() {

  // Open TFile
  // Get TTree
  // . . .

  unsigned event;
  double position;
  int id;
  std::vector<int> substructure;

  // Set Branch Addresses
  // . . .

  // Instead of doing all that stuff with selectors that
  // have pointers to the variables
  // just capture variables by reference with lambda functions
  auto cuts = std::make_tuple(
    [&]{ return position > 2; },
    [&]{ return id > 0; },
    [&]{ return substructure.size() >= 3; }
  );

  // Event loop
  // I'm emulating this part by hand below
  // You would have something like this instead
  /*
  for (Long64_t i=0; i<num_events; ++i) {
    tree->GetEntry(i);
    if (!apply_cuts(cuts)) continue;

    // Do something with selected events
    // . . .
  }
  */

  // Test events

  // Event 1
  event = 1;
  position = 65.65;
  id = 5;
  substructure = { 1,2,3,4 };

  std::cout << "Event " << event << ": "
            << (apply_cuts(cuts) ? "passed" : "rejected") << std::endl;

  // Event 2
  event = 2;
  position = 2.35;
  id = -1;
  substructure = { 1,2 };

  std::cout << "Event " << event << ": "
            << (apply_cuts(cuts) ? "passed" : "rejected") << std::endl;

}

[Wandbox] demo

std::enable_if_t<...>是来自c++14的语法糖。在c++11,你需要输入typename std::enable_if<...>::type

c++17你可以像这样写apply_cuts

template <typename T>
bool apply_cuts(T& cuts) {
  return std::apply([](auto&... x){ return (x() && ...); }, cuts);
}

以上是关于如何在C ++中实现公式模式?的主要内容,如果未能解决你的问题,请参考以下文章

如何用Python编写代码在Word中实现带公式计算过程的计算书?

如何在javascript中实现区域/代码折叠

如何在 C++ 中实现这个结果?指向数组的数组

如何在 GUI 中实现我的 while 循环以使用 Visual Studio 在 C/C++ 中保持按键

如何在 Tkinter 中实现 MVC 模式

如何在 C 中实现多分支树结构