繁体   English   中英

C++ - 两个成员函数的不同之处在于单个 function 调用

[英]C++ - Two member functions differ by a single function call

我正在尝试改进我的 C++ 编码,我想问一下以下问题的最有效和最优雅的解决方案是什么:

我实现了一个具有两个成员函数的 class。 他们都填充了一个双打数组。 这些函数的主体是相同的,只是内部有一个调用。 在其中一个中,我想调用电源 function pow(x[idx], Moment) 另一方面,我想调用另一个 class 的另一个 object 的另一个成员 function。

#include <vector>
#include <cmath>

class Pot {
  public:
    Pot() {}
    virtual double GetPot(const double x) const {return sin(x);}
    virtual ~Pot() {}
}

class BSplOper {
  private:
    const Pot *m_p;
    ... (other private members)
  public:
    BSplOper(const Pot *p) : m_p{p} {}
    virtual ~BSplOper() {}
    void MkMat1();
    void MkMat2();
}

void BSplOper::MkMat1() {
  double val = 0.0;
  for (some nested loops here) {
    ... (some more code - index transformations, etc)
    for (int indx = 0; indx < LargeNumber; indx++) {
      ... (some more nested loops)
      val += pow(x[indx], someconst);
    }
  }
}

void BSplOper::MkMat2() {
  double val = 0.0;
  for (the same code as in MkMat1) {
    ...(the same code as in MkMat1)
    for (int indx = 0; indx < LargeNumber; indx++) {
      ... (the same code as MkMat1)
      val += m_p->GetPot(x[indx]);
    }
  }
}

有什么方法可以将其实现为单个 function ,它会有一个参数来决定哪个 function 将在内部被调用? 问题是这个function会被调用很多次,它的性能真的很重要。 它位于一系列嵌套循环中。 因此,我不想在里面设置条件。

我正在考虑使用std::function作为此成员 function 的参数,它将传递对预期 function 的引用。 但是,我不确定std::function的开销。

使用模板化成员 function 会更有效吗? 就像是

template<typename F>
void BSplOper::MkMat(F fnx) {
  double val = 0.0;
  for (the same code as in MkMat1) {
    ...(the same code as in MkMat1)
    for (int indx = 0; indx < LargeNumber; indx++) {
      ... (the same code as MkMat1)
      val += (*fnx)(x[indx]);
    }
  }
}

在那种情况下,调用它的正确语法是什么? 还是这两种解决方案都完全错误? 感谢您的任何建议。

使用 function 指针的缺点是编译器可能无法进行所有可能的优化,因此您希望在编译时为编译器提供尽可能多的信息。

为此,您需要将该信息作为模板参数而不是 function 参数传递。

一种方法是将if constexpr与模板参数结合使用。

以下代码只是一个快速而肮脏的示例,说明如何做到这一点。 但是您可能想使用其他东西然后bool

struct BSplOper {

    template<bool F>
    void MkMat() {
      double val = 0.0;
      for (some nested loops here) {
        ... (some more code - index transformations, etc)
        for (int indx = 0; indx < LargeNumber; indx++) {
          ... (some more nested loops)
          
          if constexpr(F) {
            val += pow(x[indx], someconst);
          } else {
            val += m_p->GetPot(x[indx]);
          }
        }
      }
    }

    void MkMat1() {
        MkMat<true>();
    }

    void MkMat2() {
        MkMat<false>();
    }
};

if constexpr就可维护性和语义而言不是最佳解决方案。 但是如何以正确的方式解决这个问题取决于实际的代码和值依赖关系和提升时间。

但是,我不确定std::function的开销

它应该类似于虚拟呼叫。

在那种情况下,调用它的正确语法是什么?

val += (*fnx)(x[indx]); 应该只是val += fnx(x[indx]);

template <typename F>
void BSplOper::MkMat(F fnx) {
  double val = 0.0;
  for (the same code as in MkMat1) {
    ...(the same code as in MkMat1)
    for (int indx = 0; indx < LargeNumber; indx++) {
      ... (the same code as MkMat1)
      val += fnx(x[indx]);
    }
  }
}

调用类似于

MkMat([&](const auto& elem){ return pow(elem, someconst);});

还是这两种解决方案都完全错误?

他们都有优点和缺点。

它们都处理任何函子,而不仅仅是 function 指针。

  • std::function有运行时开销,但明确表达期望。
  • 模板没有开销,但没有表现力(鸭子类型)(如果需要,概念(C++20)或 SFINAE /static_assert 可能在这方面有所帮助)。 它是 header 中的模板和强制可见实现(除非显式实例化)。

一些建议function_viewstd::function std::function表现力,没有开销)。 它甚至允许在 cpp 中实现 function 作为不再模板。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM