Насколько явным должен быть при вызове конструктора?

У меня этот класс

struct foo
{
    explicit foo(const std::uint32_t& x, const std::uint32_t& y);
};

и метод

int main()
{
    std::int32_t x = -1;
    std::int32_t y = -1;
    foo f(x, y);
}

В моем компиляторе (MSVC2012) он компилируется и запускается со значениями x и y, обернутыми в беззнаковые типы. Я не ожидал этого, но ожидал ошибку компиляции из-за несоответствующих типов.

Что мне не хватает?

Ответ 1

Вам не повезло, стандарт позволяет неявное преобразование подписанного в unsigned посредством создания анонимного временного аргумента, переданного константной ссылкой.

(Обратите внимание, что это неверно для непостоянной ссылки).

Если вы используете С++ 11, лучше всего удалить конструктор, используя

foo(const std::int32_t& x, const std::int32_t& y) = delete;

Pre С++ 11 вы можете сделать этот конструктор private и не определять его. Скорее, как старомодные непереписываемые идиомы.

MSVC2012 - это своего рода компилятор С++ 03/С++ 11 на полпути. Он реализует некоторые функции С++ 11, но не другие. К сожалению, удаление конструкторов является одной из функций, которые она поддерживает не, поэтому подход private isation является наилучшим доступным для вас способом.

Ответ 2

Собственно, вы должны использовать новый синтаксис синтаксиса foo f{x, y}, который, по крайней мере, выдает предупреждение. После этого вы можете настроить свой компилятор для обработки предупреждений как ошибок и обрабатывать их соответственно, так как хороший код обычно должен также избавляться от предупреждений (потому что если вы хотели, чтобы преобразование произошло, вы должны были использовать Явное литье).

Ответ 3

explicit не препятствует неявному преобразованию с аргументами конструктора (что явно имеет место при связывании ссылок); он предотвращает неявное построение.

void bar(foo);
int main()
{
   foo f({0, 0}); // doesn't matter that the arguments are implicitly converted

   bar({0, 0});   // error - implicit conversion required here to pass a foo
   bar(f);        // crucially, ok because argument requires no conv. construction
}