【问题标题】:Explicit constructor taking multiple arguments带多个参数的显式构造函数
【发布时间】:2016-12-31 12:25:23
【问题描述】:

使构造函数具有多个参数explicit 有任何(有用的)效果吗?

例子:

class A {
    public:
        explicit A( int b, int c ); // does explicit have any (useful) effect?
};

【问题讨论】:

    标签: c++ explicit-constructor


    【解决方案1】:

    直到 C++11,是的,没有理由在多参数构造函数上使用 explicit

    这在 C++11 中发生了变化,因为初始化列表。基本上,带有初始化列表的复制初始化(但不是直接初始化)要求构造函数不被标记为explicit

    例子:

    struct Foo { Foo(int, int); };
    struct Bar { explicit Bar(int, int); };
    
    Foo f1(1, 1); // ok
    Foo f2 {1, 1}; // ok
    Foo f3 = {1, 1}; // ok
    
    Bar b1(1, 1); // ok
    Bar b2 {1, 1}; // ok
    Bar b3 = {1, 1}; // NOT OKAY
    

    【讨论】:

    • 我认为用“我为什么要那个”或“这什么时候有用”的解释来回答会更好。
    • @MateuszL Edgar 的回答可能是最好的论据,说明它为什么有用(并且可以说值得打勾)。然而,它那里的原因仅仅是因为它是explicit 现有语义的逻辑扩展。我个人不会费心制作多参数构造函数explicit
    【解决方案2】:

    你会偶然发现它用于大括号初始化(例如在数组中)

    struct A {
            explicit A( int b, int c ) {}
    };
    
    struct B {
             B( int b, int c ) {}
    };
    
    int main() {
        B b[] = {{1,2}, {3,5}}; // OK
    
        A a1[] = {A{1,2}, A{3,4}}; // OK
    
        A a2[] = {{1,2}, {3,4}}; // Error
    
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      @StoryTeller 和@Sneftel 的出色回答是主要原因。但是,恕我直言,这是有道理的(至少我这样做了),作为以后对代码进行验证的一部分。考虑你的例子:

      class A {
          public:
              explicit A( int b, int c ); 
      };
      

      此代码不会直接受益于explicit

      一段时间后,您决定为c 添加一个默认值,所以它变成了这样:

      class A {
          public:
              A( int b, int c=0 ); 
      };
      

      执行此操作时,您将关注c 参数 - 回想起来,它应该有一个默认值。您不一定要关注 A 本身是否应该被隐式构造。不幸的是,此更改使 explicit 再次相关。

      所以,为了传达一个 ctor 是 explicit,在第一次编写方法时这样做可能是值得的。

      【讨论】:

      • 但是,当维护者添加默认值并得出结果应该可用作转换构造函数时,情况会怎样呢?现在他们必须删除那个永远存在的explicit,技术支持将被关于该更改的电话淹没,并花费小时解释explicit只是噪音,并且删除它是无害的。就个人而言,我不太擅长预测未来; 现在决定界面应该是什么样子已经够难的了。
      • @PeteBecker 说得好。我个人认为这两种情况是不对称的,并且在使参数默认(或删除它们)以无意中使类隐式构造时更为常见,然后同时实际意识到回想起来应该是这样。话虽如此,这些都是“软”考虑,可能因人/项目/等而异,甚至只是品味问题。
      【解决方案4】:

      这是我对这次讨论的五分钱:

      struct Foo {
          Foo(int, double) {}
      };
      
      struct Bar {
          explicit Bar(int, double) {}
      };
      
      void foo(const Foo&) {}
      void bar(const Bar&) {}
      
      int main(int argc, char * argv[]) {
          foo({ 42, 42.42 }); // valid
          bar({ 42, 42.42 }); // invalid
          return 0;
      }
      

      如您所见,explicit 禁止使用初始化列表和bar 函数,因为struct Bar 的构造函数被声明为explicit

      【讨论】:

        猜你喜欢
        • 2017-12-31
        • 2020-02-13
        • 1970-01-01
        • 2010-11-10
        • 1970-01-01
        • 2013-12-13
        • 2013-02-05
        • 2016-02-26
        • 2011-10-08
        相关资源
        最近更新 更多