【问题标题】:Shortening multi-variable Comparisons缩短多变量比较
【发布时间】:2020-07-07 13:42:31
【问题描述】:

[这是一个有长度限制的项目,因此问题]

我有一个函数旨在返回传递的变量数量等于零。

int countZeros(int a, int b, int c, int d)
{
    int zeros = 0;
    if(a == 0)
    {
        zeros++;
    }
    if(b == 0)
    {
        zeros++;
    }
    if(c == 0)
    {
        zeros++;
    }
    if(d == 0)
    {
        zeros++;
    }
    return(zeros);
}

代码功能非常好,但是对于它所实现的目标来说很长。是否可以使用 for 循环做同样的事情?

例如:for each 0 in [data-set]{zeros++;}?

我意识到我可以在调用函数时使用 for 循环来测试每个变量,但函数是在变量声明中调用的:

addavg[x][y] = ((varA + varB + varC + varD + nums[x][y]) / (5 - (countZeros(varA, varB, varC, varD)))); 

【问题讨论】:

  • 为什么这些数字不在数组中?

标签: c++


【解决方案1】:

可变参数函数怎么样?它需要任意数量的整数。

此示例使用折叠表达式使代码更短,更易于阅读。

template <typename ...Ts> 
int countZeros(Ts ...ts)
{
   return ( !ts + ...);
}

此外,您还有这个示例用例

addavg[x][y] = ((varA + varB + varC + varD + nums[x][y]) / (5 - (countZeros(varA, varB, varC, varD))));

您可以使用与上面相同的技术来编写

template <typename ...Ts> 
int sum(Ts ...ts)
{
   return (ts + ...);
}

然后你的例子就变成了

addavg[x][y] = ((sum(varA, varB, varC, varD) + nums[x][y]) / (5 - (countZeros(varA, varB, varC, varD))));

【讨论】:

  • 请注意,折叠表达式是在 C++17 中添加的,因此这些示例不适用于 C++11 或 C++14。
【解决方案2】:

一个简单的选择就是

return ((a == 0) + (b == 0) + (c == 0) + (d == 0));

取决于您的项目的要求。对于更通用的方法,请查看使用 va_list 在函数中接受任意数量的整数。在那种情况下是的,你会想要一个循环。

【讨论】:

  • va_list 是执行此操作的 C 方法,它不是类型安全的。在 C++ 中,可变参数模板更安全。
  • 啊,我没注意标签,还以为这是一道C题
【解决方案3】:

对于您的具体示例,您可以将其缩短为以下内容:

int countZeros(int a, int b, int c, int d)
{
    return int(a == 0) + int(b == 0) + int(c == 0) + int(d == 0);
}

Live Demo

但是,可变参数模板函数会是更好的选择,然后您可以传入任意数量的参数。

@cigien's answer 向您展示了如何使用在 C++17 中添加的 fold expressions。但是如果你使用 C++11 或 C++14,你仍然可以使用可变参数模板函数,你只需要手动循环参数(参见How can I iterate over a packed variadic template argument list?),例如:

template <typename... Args> 
int countZeros(Args... args)
{
    int zeros = 0;
    for(int i : {args...}) {
        zeros += int(i == 0);
    }
    return zeros;
}

Live Demo

或者:

#include <array>
#include <algorithm>

template <typename... Args> 
int countZeros(Args... args)
{
    std::array<int, sizeof...(args)> a = {args...};
    return std::count_if(a.begin(), a.end(), [](int i){ return (i == 0); });
}

Live Demo

或者:

// for when the template parameter pack is empty...
int doCountZeros() {
    return 0;
}

template <typename Arg, typename... Args>
int doCountZeros(Arg firstArg, Args... otherArgs) {
    return int(firstArg == 0) + doCountZeros(otherArgs...);
}

template <typename... Args>
int countZeros(Args... args) {
    return doCountZeros(args...);
}

Live Demo

这些方法中的任何一种都可以很好地处理您的 countZeros(varA, varB, varC, varD) 示例。


您的示例还显示了 4 个变量的总和。这也可以用函数来处理,例如:

int sum(int a, int b, int c, int d)
{
    return a + b + c + d;
}

Live Demo

或者更好,通过可变参数函数。如果你没有使用 C++17 折叠表达式,你可以手动循环参数,类似于上图(另见Add all parameters with parameter pack expansion),例如:

template <typename... Args> 
int sum(Args... args)
{
    int result = 0;
    for(int i : {args...}) {
        result += i;
    }
    return result;
}

Live Demo

或者:

#include <array>
#include <numeric>

template <typename... Args> 
int sum(Args... args)
{
    std::array<int, sizeof...(args)> a = {args...};
    return std::accumulate(a.begin(), a.end(), 0);
}

Live Demo

或者:

int doSum() {
    return 0;
}

template <typename Arg, typename... Args>
int doSum(Arg firstArg, Args... otherArgs) {
    return firstArg + doSum(otherArgs...);
}

template <typename... Args>
int sum(Args... args) {
    return doSum(args...);
}

Live Demo

这些方法中的任何一种都可以让您在需要时使用sum(varA, varB, varC, varD)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-07
    • 1970-01-01
    • 2014-03-09
    • 1970-01-01
    相关资源
    最近更新 更多