简体   繁体   English

如何使用 matlab 数据 Z8A5DA52ED126447D359E70A8A55 中的可变数量字段在 C++ 中初始化 object

[英]How can I initialize an object in C++ using a variable number of fields from a matlab data api struct

I am building a matlab MEX function using the matlab c++ data api . I am building a matlab MEX function using the matlab c++ data api . My mex function accepts a struct with some fields of varying size, type and name as an input.我的 mex function 接受一个结构,其中包含一些不同大小、类型和名称的字段作为输入。 The exact makeup of this struct could vary and is defined outside the scope of the program, but I know all the possible combinations of the constituent fields ahead of time.这个结构的确切组成可能会有所不同,并且在程序的 scope 之外定义,但我提前知道组成字段的所有可能组合。 We will call this parameter called 'Grid', and Grid is passed to a helper function.我们将此参数称为“Grid”,并将 Grid 传递给帮助程序 function。

In this helper function, I would like to generate an instance of a derived class where the specific type of derived class will either depend on/correspond to the specific combination of the fields of Grid.在这个助手 function 中,我想生成一个派生 class 的实例,其中派生 class 的特定类型将取决于/对应于 Grid 的特定组合。 The idea is that I can extract the fields of Grid and use them to create the instance of the correct derived class.这个想法是我可以提取 Grid 的字段并使用它们来创建正确的派生 class 的实例。 I would like to achieve this without the need to rewrite my code every time I add a new derived class with a different possible combination of fields.我希望在每次添加具有不同可能字段组合的新派生 class 时都无需重写代码即可实现此目的。 How could I do this?我怎么能这样做? I am open to alternate approaches and strategies as well.我也对替代方法和策略持开放态度。

For example, Grid might be defined in the matlab environment like:例如,网格可能在 matlab 环境中定义,如:

Grid = struct('XPSF',X(:),'ZPSF',Z(:),'xe',Trans.ElementPos(:,1)*wvlToM,'TXDelay',TXdelay(:,8));

Then handled by the mex function and passed to the helper function whose definition looks like:然后由 mex function 处理并传递给助手 function ,其定义如下:

void extractFields(matlab::data::StructArray& Grid);

Currently, Grid can also be composed of a single value in place of XPSF or ZPSF.目前,Grid 也可以由单个值组成,而不是 XPSF 或 ZPSF。 I anticipate possibly adding other fields to Grid in the future.我预计将来可能会在 Grid 中添加其他字段。 For each of these possible combinations, I have a derived class that has some unique overridden functions:对于这些可能的组合中的每一个,我都有一个派生的 class 具有一些独特的重写功能:

class Beamform {
    public:
    //Constructor    
    Beamform();
    
    virtual ~Beamform() {}
    template <typename T> int sgn(T val) { return (T(0) < val) - (val < T(0)); }
    virtual void calcIDXT(...);
};

class bfmPlaneWave : public Beamform 
{
    public:
    double theta;
    Eigen::VectorXd xe, XPSF, ZPSF, dTX;
    
    template<typename Derived>
    bfmPlaneWave(double& angle, ...);

    template<typename Derived>
    void calcIDXT(...) override;
};

class bfmXRflMTX : public Beamform {
    public:
    double theta, zCoord;
    Eigen::VectorXd xe, XPSFin, XPSFout, dTX;

    template<typename Derived>
    bfmXRflMTX(double& angle, ...);

    template<typename Derived>
    void calcIDXT(...) override;
};

class bfmZRflMTX : public Beamform {
    public:
    double theta, xCoord;
    Eigen::VectorXd xe, ZPSFin, ZPSFout, dTX;

    template<typename Derived>
    bfmXRflMTX(double& angle, ...);

    template<typename Derived>
    void calcIDXT(...) override;
};

I would start by declaring a common pattern for construction.我将首先声明一个通用的构造模式。 Something like this:像这样的东西:

class Beamform
{
public:
  virtual void calcIDXT(...) = 0;
  virtual ~Beamform() = default;
};

class bfmPlaneWave: public Beamform
{
public:
  /** Return nullptr if not compatible */
  static bfmPlaneWave* fromGrid(matlab::data::StructArray&);
  virtual void calcIDXT(...) override;
};

class bfmXRflMTX: public Beamform
{
public:
  /** Return nullptr if not compatible */
  static bfmXRflMTX* fromGrid(matlab::data::StructArray&);
  virtual void calcIDXT(...) override;
};

Then you could have a simple, central factory function that you extend as required:然后,您可以拥有一个简单的中央工厂 function,您可以根据需要对其进行扩展:

/**
 * Option 1: Use a central dispatch function which can be updated with a
 * simple two-liner
 */
std::unique_ptr<Beamform> beamformForGrid(matlab::data::StructArray& Grid)
{
  std::unique_ptr<Beamform> rtrn;
  if(rtrn.reset(bfmPlaneWave::fromGrid(Grid)), rtrn != nullptr)
    return rtrn;
  if(rtrn.reset(bfmXRflMTX::fromGrid(Grid)), rtrn != nullptr)
    return rtrn;
  // insert more here
  return rtrn;
}

However, if I understand you correctly, this is something that you don't want.但是,如果我对您的理解正确,这是您不想要的。 In that case you could use a central registry and global constructors.在这种情况下,您可以使用中央注册表和全局构造函数。 Global constructors (those for global variables) are run when a DLL is loaded.加载 DLL 时运行全局构造函数(用于全局变量的构造函数)。 This is similar to how for example CppUnit registers its unit tests.这类似于 CppUnit 注册其单元测试的方式。

class AbstractBeamformFactory
{
public: 
  virtual ~AbstractBeamformFactory() = default;
  /** Return nullptr if not compatible */
  virtual Beamform* fromGrid(matlab::data::StructArray&) = 0;
};
/**
 * Registers existing factories
 *
 * Follows the singleton pattern.
 * Yes, it is frowned upon, but if it works, it works.
 */
class BeamformRegistry
{
  /**
   * Protects the list of factories
   *
   * A bit overkill seeing how neither Matlab nor global constructors are
   * particularly multithreaded, but better safe than sorry
   */
  mutable std::mutex mutex;
  std::vector<AbstractBeamformFactory*> factories;
public:
  /**
   * Retrieves singleton instance
   * 
   * This isn't a global variable because we need to use it in other
   * global constructors and we can't force a specific order between
   * global constructors
   */
  static BeamformRegistry& globalInstance();

  void add(AbstractBeamformFactory* factory)
  {
    std::lock_guard<std::mutex> lock(mutex);
    factories.push_back(factory);
  }
  void remove(AbstractBeamformFactory* factory)
  {
    std::lock_guard<std::mutex> lock(mutex);
    factories.erase(std::find(factories.begin(), factories.end(), factory));
  }
  std::unique_ptr<Beamform> beamformForGrid(matlab::data::StructArray& Grid) const
  {
    std::unique_ptr<Beamform> rtrn;
    std::lock_guard<std::mutex> lock(mutex);
    for(AbstractBeamformFactory* factory: factories)
      if(rtrn.reset(factory->fromGrid(Grid)), rtrn != nullptr)
        break;
    return rtrn;
  }
};
/**
 * Implements AbstractBeamformFactory for a specific type of beamformer
 *
 * Create a global variable of this type in order to add it to the global
 * BeamformRegistry
 */
template<class BeamformImplementation>
class BeamformFactory: public AbstractBeamformFactory
{
  bool registered;
public:
  explicit BeamformFactory(bool registerGlobal=true)
    : registered(registerGlobal)
  {
    /* don't move this to the base class to avoid issues around
     * half-initialized objects in the registry
     */
    if(registerGlobal)
      BeamformRegistry::globalInstance().add(this);
  }
  virtual ~BeamformFactory()
  {
    if(registered)
      BeamformRegistry::globalInstance().remove(this);
  }
  virtual Beamform* fromGrid(matlab::data::StructArray& Grid) override
  { return BeamformImplementation::fromGrid(Grid); }
};

/* in CPP files */
BeamformRegistry& BeamformRegistry::globalInstance()
{
  static BeamformRegistry instance;
  return instance;
}
/*
 * Make global variables to add entries to registry.
 * These can be scattered across different cpp files
 */
BeamformFactory<bfmPlaneWave> planeWaveFactoryInstance;
BeamformFactory<bfmXRflMTX> XRflMTXFactoryInstance;

Now you can simply call BeamformRegistry::globalInstance().beamformForGrid(Grid) to access all registered beamform implementations and to extend the number of implementations, you just scatter factory instances across your cpp files.现在您可以简单地调用BeamformRegistry::globalInstance().beamformForGrid(Grid)来访问所有已注册的波束形成实现并扩展实现的数量,您只需将工厂实例分散到您的 cpp 文件中。

One thing I'm unsure about is how this interacts with MEX.我不确定的一件事是它如何与 MEX 交互。 When does Matlab load its extensions? Matlab 何时加载其扩展? If this only happens in some form of lazy fashion, the global constructors may not execute soon enough.如果这仅以某种形式的惰性方式发生,则全局构造函数可能不会很快执行。 I guess it is worth checking with a few print statements.我想值得用一些打印语句检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将结构字段从 Matlab 加载到 C++? - How can I load struct fields from Matlab to C++? 我应该如何从 C++ 正确初始化 C 结构? - How should I properly initialize a C struct from C++? 如何在C ++中正确初始化Struct对象 - How to properly initialize Struct object in c++ 如何在C ++中新建和初始化结构? - How can I new and initialize a struct in C++? 如何在C ++中初始化本地结构对象(无法将新对象创建为本地变量)? - How to initialize a local struct object in C++ (cannot create a new object as a local variable)? 如何初始化 C 中的结构中的所有对象,就像构造函数初始化 C++ 中的所有 class 对象一样? - How can I initialize all objects from a struct in C the way constructor initializes all class objects in C++? C ++如何从uchar数组填充结构的位字段? - C++ How can i fill the bit fields of a struct from a uchar array? 如何在 C++ 中将结构初始化为 0 - How to initialize a struct to 0 in C++ C ++初始化使用“ new”关键字分配的结构的对象成员 - C++ Initialize object member of a struct that is allocated using the “new” keyword 我可以使用C ++中的函数来初始化类成员变量吗? 如果可以,该怎么办? - Can I initialize a class member variable using function in C++? If so how to do it?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM