函数作为模板参数,根据方法具有不同的结构

Function as template argument that has a different structure depending on method

我正在编写一个例程来查找 C++ 中函数的数值根。根据算法,我可以提供函数或同时提供函数和导数。比如我有两个独立的例程

template <typename T, typename Func>
T Bisection(Func func, T x) {
  // algorithm details...

  auto f = func(x);

  // more details...
}

template <typename T, typename Func>
T Newton(Func func, T x) {
  // algorithm details...

  auto [f, df] = func(x);

  // more details...
}

请注意,一种方法假设 Func 类型是一个简单的单变量函数,而另一种方法假设它是包含函数 'f' 和导数 'df' 的某种结构。到目前为止,这两个例程似乎都适用于我的测试。

我想编写一个接受参数方法的主例程,该方法使用 switch 语句选择其中一个。我的想法是:

enum Method {
  Bisection, Newton
};

template <typename T, typename Func>
T find_root(Func func, T x, Method method) {
  switch(method) {
  case Bisection: return Bisection(func, x);
  case Newton: return Newton(func, x);
  default: // do other stuff...
  }
}

这不编译。例如,如果我使用 method = Bisection 编写例程,我会收到错误 error: cannot decompose non-array non-class type 'const float',因为 Newton 方法需要不同的绑定结构,即使我没有使用它。有没有一种通用的方法可以绕过这个以允许统一的主方法?我有另一种方法,用户提供函数以及一阶和二阶导数,因此该结构具有三个组件。

问题是,在您的情况下,您正在为不适合实现的类型实例化这两个函数。您可以尝试 if constexpr,但对于这种情况,您需要将 method 参数移至模板参数:

enum class Method {
    Bisection, Newton
};

template <Method method, typename T, typename Func>
T find_root(Func func, T x) {
    if constexpr (method == Method::Bisection) {
        return Bisection(func, x);
    }
    else if constexpr (method == Method::Newton) {
        return Newton(func, x);
    }
    else {
    }
}

在这种情况下,编译器不会为表达式为假的分支实例化函数(请注意,编译器要消除假分支,表达式需要依赖于模板参数)。