【问题标题】:Better way to pass bool variable as parameter?将布尔变量作为参数传递的更好方法?
【发布时间】:2015-09-23 15:50:38
【问题描述】:

我想知道是否有更好的方法来编写它以提高可读性。 如果你有下面这样的功能,

void animal(bool hasFourLegs, bool hasHead, bool hasBody);

当你调用函数时,你会得到类似的东西

animal(true, false, true);

这让我每次遇到这样的函数时都去看看定义。

所以...

我做这样的事情!

const bool HAS_FOURLEGS = true;
const bool NO_HEAD = false;
const bool HAS_BODY = true;

animal(HAS_FOURLEGS, NO_HEAD, HAS_BODY);

但我不喜欢每次调用函数时都声明const bool

CPP 好像不支持类似的东西

animal(bool hasFourlegs = true, bool hasHead = false, bool hasBody = true);

有没有更好更短的方法?

【问题讨论】:

  • 根据经验,不要以全大写字母样式声明变量。它通常用于宏
  • 这就是为什么拥有一个好的 IDE 很重要。只需悬停即可看到函数签名
  • 函数的签名正是你的 IDE 应该告诉你的——不要使用纯文本编辑器
  • 我将 vim 与 YouCompleteMe 一起使用。当我进行编码时,它工作得很好。但是当我阅读时,哦,伙计..大声笑
  • 为什么没有动物类?当然,问题可能会转移到该类的构造函数。但是枚举解决方案非常适合。

标签: c++ readability


【解决方案1】:

当我遇到与此相关的问题时,我有时会创建一个 enum,即使只有 2 个预期的选择:

例如,代替下面的函数声明:

bool search(..., bool recursive);

我会选择:

enum class SearchOpt
{
    Recursive,
    NonRecursive
};

bool search(..., SearchOpt opt);

因此,调用语法从:

bool found = search(..., true);

到:

bool found = search(..., SearchOpt::Recursive);

注意:这样可以避免每次调用函数时都必须创建自己的常量。

编辑

正如其他人所建议的那样,将单个 enum 配置为位标志是有意义的,而不是为每个选项单独设置 bools,从而为每个选项单独设置 enum

【讨论】:

    【解决方案2】:

    使用标志:

      enum {
        HAS_LEGS = 0x01,
        HAS_HEAD = 0x02,
        HAS_BODY = 0x04,
      };
    
      void animal(int properties);
    
      animal(HAS_LEGS | HAS_HEAD);
    

    【讨论】:

    • 然后使用 Qt 库中的 QFlags 等类型安全、内省感知的标志。或者重载operator<<等一些操作符来创建类工厂。
    • @SergeyA:从某种意义上说,它们非常快,编码时间短,代码行数更少,同时保持代码可读性,随着时间的推移保持接口稳定? ;-p
    • @cfi,不是真的。从某种意义上说,它们正在污染命名空间(HAS_LEGS 仅对 animal() 有意义,但对其他人可见(是的,我知道类枚举),它们很难维护,在查看调用堆栈时它们很神秘...够了吗?
    【解决方案3】:

    另一种选择是使用一个类来保存它们密切相关的参数:

    struct AnimalOptions {
      bool hasHead, hasBody, hasLegs;
      AnimalOptions() : hasHead(false), hasBody(false), hasLegs(false);
    }
    
    ...
    
    AnimalOptions opt;
      opt.hasHead = true;
    
      animal(opt);
    

    当你有一个函数似乎需要一堆具有相同类型的参数时,这种技术很有用,它们的顺序不容易记住。当您的函数需要多个 ints 时,它同样有用。

    【讨论】:

    • 使用更多样板,可以链接修改:AnimalOptions().hasHead(false).hasBody(true)
    【解决方案4】:

    作为其他答案的替代方案,我喜欢 Andrzej Krzemieński 在他的博客上提出的 tagged_bool

    【讨论】:

      【解决方案5】:

      奇怪的是没有人建议来自 Boost.parameter 的命名参数:http://www.boost.org/doc/libs/1_59_0/libs/parameter/doc/html/index.html

      【讨论】:

      • 老实说,我从未在现实世界的代码中见过 Boost.parameter :-}
      • 这感觉就像使用原子弹来破解坚果一样。 (同样,从未见过有人真正使用它)
      【解决方案6】:

      评论是你的朋友!

      animal(   true,   //hasFourLegs
                false,  //hasHead
                true    //hasBody
            );
      

      【讨论】:

      • 这样的cmets无法弥补糟糕的代码。不要写评论写可读的代码。
      • 这将进入我的“最差评论”比赛的排行榜。虽然第一个位置是固定为 "++i; // Increment i" cmets 而第二个位置是由 class A { A(); // 构造函数 this 也是值得注意的例子。
      • 对于作为可变 & 传递的参数,这与 /*ref*/ 属于同一类别。这就是 C# 引入关键字“ref”的原因,因此必须对调用者进行注释。布尔参数的问题是同样的问题——我们希望语言强制调用站点被注释。对我来说,这似乎是 IDE 问题,而不是语言问题。
      【解决方案7】:

      您可以使用按位值,如下所示:

      const int hasLegs = 0x01;
      const int noHead = 0x02;
      const int hasBody = 0x04;
      

      然后使用上述任意组合调用animal,例如: 动物(hasLegs + hasBody);

      使用单个 int 参数标记 animal

      inside `animal`, test the bits:
      if (parameter & haasBody)
      {
          // it has a body....
      }
      

      【讨论】:

        【解决方案8】:

        C++20 将 designated initializers 作为聚合初始化的一部分。您可以使用布尔参数创建一个结构并按值传递该结构。您甚至可以使用默认参数值。

        struct AnimalParts {
            bool hasFourLegs = false;
            bool hasHead = true;
            bool hasBody = true;
        }
        
        void animal(AnimalParts parts);
        

        然后像这样使用它:

        animal({.hasFourLegs = true, .hasHead = false});
        

        这与您建议的命名参数习语非常接近。在编译方面,这两个选项似乎产生了相当的输出,请参阅Godbolt

        【讨论】:

          【解决方案9】:

          我不确定这是一个正确的方法,但我仍然忍不住分享这个想法。

          让我们想象一下,这个函数不是你的,而是来自一些很难更改的流行 API。

          void animal(bool hasFourLegs, bool hasHead, bool hasBody);
          

          在这种情况下,可以这样称呼它:

          animal(bool("hasFourlegs"), !bool("hasHead"), bool("hasBody"));
          

          C 字符串总是一个非零指针,它被转换为true

          一个可能的缺点是编译时间...? 另一个是代码行长度的增加...

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-13
            • 2018-09-03
            • 1970-01-01
            • 2012-11-13
            • 1970-01-01
            相关资源
            最近更新 更多