C++ variadic模板将修改的参数传递到功能

发布于 2025-02-12 09:37:22 字数 1433 浏览 0 评论 0原文

我正在努力处理以下代码。它本来应该是一个非常简单的,希望constexpr,渐变求解器。

我当前的代码看起来像这样:

typedef std::function<double(double, double, double)> residual_function_t;

double gradient_descent(const residual_function_t& res_fun, double step_size, double& x, double& y, double& z,
                        double epsilon = 0.01) {
  assert(step_size > 0.0);

  const auto residual = res_fun(x, y, z);

  const auto deriv_x = (res_fun(x + epsilon, y, z) - residual) / epsilon;
  const auto deriv_y = (res_fun(x, y + epsilon, z) - residual) / epsilon;
  const auto deriv_z = (res_fun(x, y, z + epsilon) - residual) / epsilon;

  x -= std::copysign(step_size, deriv_x);
  y -= std::copysign(step_size, deriv_y);
  z -= std::copysign(step_size, deriv_z);

  return residual;
}

我想使功能更加通用,并接受任何类型的功能。这意味着我必须为要传递给该功能的每个参数创建变量,例如deriv_x

我希望我的功能签名是这样的:

template<typename residual_function_t, typename... Arg_types>
double gradient_descent(const residual_function_t & res_fun, double step_size, Arg_types... arguments) {
constexpr auto epsilon = 0.01;

const auto residual res_fun(arguments...);

// Here I want to calculate deriv_x/y/z/etc for every argument passed.

// Here want to assign x/y/z, or return them if needed, for every argument passed.

return residual;
}

我想知道这是否可能吗?如果它使生活更容易假设所有参数类型double,那也将有效。

I'm struggling with the following code. It's meant to be a very simple, hopefully constexpr, gradient-descent solver.

My current code looks like this:

typedef std::function<double(double, double, double)> residual_function_t;

double gradient_descent(const residual_function_t& res_fun, double step_size, double& x, double& y, double& z,
                        double epsilon = 0.01) {
  assert(step_size > 0.0);

  const auto residual = res_fun(x, y, z);

  const auto deriv_x = (res_fun(x + epsilon, y, z) - residual) / epsilon;
  const auto deriv_y = (res_fun(x, y + epsilon, z) - residual) / epsilon;
  const auto deriv_z = (res_fun(x, y, z + epsilon) - residual) / epsilon;

  x -= std::copysign(step_size, deriv_x);
  y -= std::copysign(step_size, deriv_y);
  z -= std::copysign(step_size, deriv_z);

  return residual;
}

I'd like to make the function more general, and accept any kind of function. That means I have to create variables like deriv_x for each of the arguments I want to pass to that function.

I'd like my function signature to be something like this:

template<typename residual_function_t, typename... Arg_types>
double gradient_descent(const residual_function_t & res_fun, double step_size, Arg_types... arguments) {
constexpr auto epsilon = 0.01;

const auto residual res_fun(arguments...);

// Here I want to calculate deriv_x/y/z/etc for every argument passed.

// Here want to assign x/y/z, or return them if needed, for every argument passed.

return residual;
}

I wonder if this is possible? If it makes life easier to assume all arguments are of type double, that would also work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

别再吹冷风 2025-02-19 09:37:22

如果您希望所有参数均为双型,那么您可以考虑使用std :: prinistizer_list如下:

double gradient_descent(const residual_function_t& res_fun,
                        double step_size,
                        std::initializer_list<double> args,
                        double epsilon = 0.01) {
    // ...

缺点是您必须围绕args添加一组额外的括号调用功能时。否则,虽然不是严格要求,但您可能需要在variadic参数列表之前移动epsilon以简化您的生活。您有许多处理模板参数包的选择。您可以在C ++ 17或以后可以做的一件简单的事情是将参数放入一个数组中:

double gradient_descent(const residual_function_t& res_fun,
                        double step_size,
                        double epsilon,
                        auto ...argspack) {
    std::array<double, sizeof...(argspack)> args(double(argspack)...);
    // ...
}

如果您想修改参数,那也很好,尽管当时它们必须是双打:

double gradient_descent(const residual_function_t& res_fun,
                        double step_size,
                        double epsilon,
                        std::same_as<double> auto &...argspack) {
    std::array<std::reference_wrapper<double>, sizeof...(argspack)> args(std::as_ref(argspack)...);
    // ...
}

If you want all the arguments to be of type double, then you might consider using std::initializer_list as follows:

double gradient_descent(const residual_function_t& res_fun,
                        double step_size,
                        std::initializer_list<double> args,
                        double epsilon = 0.01) {
    // ...

The downside is that you have to add an extra set of braces around the args when calling the function. Otherwise, while not strictly required, you may want to move epsilon before the variadic argument list to simplify your life. You have many options for handling a template parameter pack. One simple thing you can do in C++17 or later is to put the arguments into an array:

double gradient_descent(const residual_function_t& res_fun,
                        double step_size,
                        double epsilon,
                        auto ...argspack) {
    std::array<double, sizeof...(argspack)> args(double(argspack)...);
    // ...
}

If you want to modify the arguments, that's fine, too, though they have to be doubles at that point:

double gradient_descent(const residual_function_t& res_fun,
                        double step_size,
                        double epsilon,
                        std::same_as<double> auto &...argspack) {
    std::array<std::reference_wrapper<double>, sizeof...(argspack)> args(std::as_ref(argspack)...);
    // ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文