Почему явно разрешено для конструкторов и конструкторов по умолчанию с 2 или более (не по умолчанию) параметрами? - PullRequest
32 голосов
/ 17 декабря 2010

Я понимаю, что конструкторы с одним (не заданным по умолчанию) параметром действуют как неявные преобразователи, которые преобразуют этот тип параметра в тип класса. Тем не менее, explicit может использоваться для квалификации любого конструктора, без параметров (конструктор по умолчанию) или с 2 или более (не по умолчанию) параметрами.

Почему явно разрешено для этих конструкторов? Есть ли пример, где это полезно для предотвращения неявного преобразования какого-либо рода?

Ответы [ 4 ]

37 голосов
/ 17 декабря 2010

Одна из причин, конечно, в том, что это не больно.

Одной из причин, по которой это необходимо, является наличие аргументов по умолчанию для первого параметра. Конструктор становится конструктором по умолчанию, но все еще может использоваться как конструктор преобразования

struct A {
  explicit A(int = 0); // added it to a default constructor
};

C ++ 0x фактически использует его для многопараметрических конструкторов. В C ++ 0x для инициализации объекта класса можно использовать список инициализаторов . Философия

  • если вы используете = { ... }, то вы инициализируете объект с помощью своего рода «составного значения», которое концептуально представляет абстрактное значение объекта и которое вы хотите преобразовать в тип.

  • если вы используете инициализатор { ... }, вы напрямую вызываете конструкторы объекта, не обязательно желая указать преобразование.

Рассмотрим этот пример

struct String {
    // this is a non-converting constructor
    explicit String(int initialLength, int capacity);
};

struct Address {
    // converting constructor
    Address(string name, string street, string city);
};

String s = { 10, 15 }; // error!
String s1{10, 15}; // fine

Address a = { "litb", "nerdsway", "frankfurt" }; // fine

Таким образом, C ++ 0x показывает, что решение C ++ 03 разрешить явное для других конструкторов вовсе не было плохой идеей.

7 голосов
/ 17 декабря 2010

Возможно, это было для поддержки обслуживания.Используя explicit в конструкторах с несколькими аргументами, можно избежать непреднамеренного введения неявных преобразований при добавлении значений по умолчанию к аргументам.Хотя я не верю этому;вместо этого я думаю, что в C ++ допускается множество вещей, чтобы просто не сделать определение языка более сложным, чем оно уже есть.

Возможно, самый печально известный случай - возвращение ссылки на не- staticлокальная переменная.Потребовались бы дополнительные сложные правила, чтобы исключить все «бессмысленные» вещи, не затрагивая ничего другого.Так что это просто разрешено, получая UB, если вы используете эту ссылку.

Или для конструкторов, вы можете определить любое количество конструкторов по умолчанию, если их сигнатуры различаются, но с большим количествомчем один, довольно сложно иметь любой из них по умолчанию.: -)

Возможно, лучше задать вопрос, почему explicit также не разрешен для операторов преобразования?

Что ж, так будет и в C ++ 0x.Так что не было веской причины, почему бы и нет.Фактическая причина, по которой нельзя разрешить explicit операторам конверсии, может быть столь же прозаичной, как и надзор, или борьба за принятие explicit, в первую очередь, или простая расстановка приоритетов времени комитета, или что-то еще.Приветствия & hth.,

7 голосов
/ 17 декабря 2010

Это, вероятно, просто удобство; нет никаких оснований для dis - разрешать это, так зачем создавать трудности для генераторов кода и т. д.? Если вы проверили, то процедуры генерации кода должны иметь дополнительный шаг, проверяющий, сколько параметров имеет сгенерированный конструктор.

Согласно различным источникам , он вообще не действует при применении к конструкторам, которые не могут быть вызваны только одним аргументом.

5 голосов
/ 17 декабря 2010

Согласно Стандарту кодирования High Integrity C ++ вы должны объявить весь конструктор параметра sinlge как явный во избежание случайного использования при преобразованиях типов . В случае, если это конструктор с несколькими аргументами, предположим, что у вас есть конструктор, который принимает несколько параметров, каждый из которых имеет значение по умолчанию, преобразуя конструктор в некий конструктор по умолчанию, а также конструктор преобразования:

class C { 
    public: 
    C( const C& );   // ok copy 
    constructor C(); // ok default constructor 
    C( int, int ); // ok more than one non-default argument 

    explicit C( int ); // prefer 
    C( double ); // avoid 
    C( float f, int i=0 ); // avoid, implicit conversion constructor 
    C( int i=0, float f=0.0 ); // avoid, default constructor, but 
                               // also a conversion constructor 
}; 
void bar( C const & ); 
void foo() 
{ 
    bar( 10 );  // compile error must be 'bar( C( 10 ) )' 
    bar( 0.0 ); // implicit conversion to C 
}
...