【问题标题】:Can I create a function which takes any number of arguments of the same type?我可以创建一个接受任意数量相同类型参数的函数吗?
【发布时间】:2021-11-18 03:32:01
【问题描述】:

所以基本上,我想创建一个这样的函数:

total_sum(1, 2, 5, 4, 2) // return 14
total_sum(5, 6, 2) // return 13

我可以使用的一种方法是省略号,如下所示:

#include <cstdarg>
int total_sum(int count, ...)
{
    int sum{0};
    va_list list;
    va_start(list, count);
    for (int arg{0}; arg < count; ++arg)
    {
         sum += va_arg(list, int);
    }
    va_end(list);
    return sum;
}

但是当我调用total_sum() 时,我必须提供一个额外的参数。所以在示例中,我必须调用:

total_sum(5, 1, 2, 5, 4, 2);
total_sum(3, 5, 6, 2);

我不太喜欢。另外,省略号真的很容易出错,所以我想远离它们。

我能想到的另一种方法是使用一些容器:

#include <vector>
int total_sum(std::vector<int> values)
{
    int sum{0};
    for(const auto &i : values)
    {
       sum += i;
    }
    return sum;
}

我这样称呼它:

total_sum({1, 2, 5, 4, 2});
total_sum({3, 5, 6, 2});

但是,我不想有那些花括号,那我该怎么办?是否有一些 C++ 功能允许我这样做?


一些相关链接:restrict variadic template argumentsfold expressionparameter packsa C++11 "equivalent" of fold expressions

【问题讨论】:

  • 您可以使用宏为您的total_sum 函数提供计数。像这样的东西:stackoverflow.com/a/2124433/11613622
  • 如果参数个数有最大值,可以使用可选参数-每个参数的默认值-,如果你发送一个值它会使用它,否则它是默认值分配给。例如默认值为 0,它对求和运算没有任何影响

标签: c++


【解决方案1】:

使用 C++17 fold expression:

template<class... Args>
constexpr auto total_sum(const Args&... args) {
  return (args + ... + 0);
}

static_assert(total_sum(1, 2, 5, 4, 2) == 14);
static_assert(total_sum(3, 5, 6, 2) == 16);

【讨论】:

  • 为什么是+ 0
  • 为了使total_sum()也是一个有效的表达式。
【解决方案2】:

在 C++11 和更高版本中,您可以使用 template parameter packs 创建递归实现,如下所示:

#include <iostream>

// base function
int total_sum()
{
    return 0;
}

// recursive variadic function
template<typename T, typename... Targs>
int total_sum(T firstValue, Targs... Fargs)
{
    return firstValue + total_sum(Fargs...);
}

int main(int, char **)
{
   int s = total_sum(1, 5, 10, 20);
   std::cout << "sum is:  " << s << std::endl;
   return 0;
}

运行上述程序会产生以下输出:

sum is:  36

【讨论】:

  • 递归模板可变参数往往编译速度较慢。折叠表达式 (C++17)(或 C++11 “等价物”)是首选。
  • @Jarod42,c++11中等效的方法是什么?
  • @Elliott:类似于int sum = 0; const int dummy[] = {0, (sum += args)...}; return sum;
【解决方案3】:

以下所有代码均基于this文章。


您也可以执行这种 C++11“等效”的折叠表达式:

#include <iostream>
#include <algorithm>
#include <utility>
#include <type_traits>
/*
Overload a total_sum() function with no arguments.
so it works when calling total_sum() with no argument.
*/
int total_sum()
{
    return 0;
}

template<typename ... I>
int total_sum(const I &... i)
{
    int result{};
    static_cast<void>(std::initializer_list<int>{(result += i, 0)... });
    return result;
}

int main()
{
    std::cout << total_sum() << '\n';
    std::cout << total_sum(1, 2, 5, 4, 2) << '\n';
    std::cout << total_sum(5, 6, 2) << '\n';
}

See this online!

这个可以添加任何可以转换为可添加值的东西:

#include <iostream>
#include <algorithm>
#include <utility>
#include <type_traits>

int total_sum()
{
    return 0;
}

template<typename ... V>
typename std::common_type<V...>::type total_sum(const V &... v)
{
    typename std::common_type<V...>::type result = {};
    static_cast<void>(std::initializer_list<int>{ (result += v, 0)... });
    return result;
}
int main()
{
    std::cout << total_sum() << '\n';
    std::cout << total_sum(5, 6, 2) << '\n';
}

See this online!

上面的代码使用 C++14 可以更简洁:

#include <iostream>
#include <algorithm>
#include <utility>
#include <type_traits>

int total_sum()
{
    return 0;
}
template<typename ... V>
auto total_sum(const V &... v) {
  std::common_type_t<V...> result = {};
  static_cast<void>(std::initializer_list<int>{ (result += v, 0)... });
  return result;
}
int main()
{
    std::cout << total_sum() << '\n';
    std::cout << total_sum(5, 6, 2) << '\n';
}

See this online!

【讨论】:

    猜你喜欢
    • 2013-08-24
    • 2013-07-14
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 2013-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多