如何在C 中实现公式模式

How to implement a formula pattern in C++?

本文关键字:模式 实现      更新时间:2023-10-16

免责声明

首先,我为这个问题的标题感到非常抱歉。我简单地制定想要的东西并不容易。如果您知道如何更改它 - 请,建议。

问题描述

预序

我有大量的结构化数据,这是不同类型的变量的树(root ttree对象)。该数据的基本单元被称为 entry 事件。因此,不同的条目包含相同变量的不同值。后者不是最清晰的声明。以下面的方式考虑那棵树:就像矩阵一样,行是条目编号(0、1、2,...),列是可变名称( energy 动量 theta ,...)。

我们需要的

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

我们正在按事件进行选择活动。IE。每个事件都通过每个选择器,如果其中某些选项失败(未传递)(选择器)(选择器)转弯。

编程问题

每个选择器由从抽象基类得出的类表示:

 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);
}