微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C++ - 两个成员函数的区别在于单个函数调用

如何解决C++ - 两个成员函数的区别在于单个函数调用

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

我实现了一个具有两个成员函数的类。它们都填充了一个双打数组。除了内部深处的一个调用之外,这些函数的主体是相同的。其中之一,我想调用函数pow(x[idx],Moment)。另一方面,我想调用一个类的另一个对象的另一个成员函数

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

有没有办法将其实现为单个函数,该函数将有一个参数决定将在内部调用哪个函数?问题是这个函数会被调用很多次,它的性能非常重要。它位于一系列嵌套循环内。因此,我不想在里面放条件。

我想使用 std::function 作为这个成员函数的参数,它将传递对预期函数的引用。但是,我不确定 std::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]);
    }
  }
}

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

解决方法

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

为此,您可以将该信息作为模板参数而不是函数参数传递。

一种方法是将 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);});

或者这两种解决方案都完全错误?

两者各有利弊。

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

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

有些人建议 function_viewstd::function 的非拥有版本,具有 std::function 的表现力,没有开销)。 它甚至允许在 cpp 中实现该功能不再是模板。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。