В ошибочной строке используется синтаксис инициализации списка:
auto a = std::bitset<20>{cell}; //fails
Этот синтаксис определен в Разделе 11.6.4 стандарта C ++ 17. Соответствующая часть:
Список-инициализация объекта или ссылки типа T
определяется следующим образом:
...
(3.7) В противном случае , если T
является типом класса, рассматриваются конструкторы. Применимые конструкторы перечисляются, и лучший выбирается через разрешение перегрузки (16.3, 16.3.1.7). Если для преобразования какого-либо из аргументов требуется сужающее преобразование (см. Ниже), программа имеет некорректную форму.
...
Сужающее преобразование является неявное преобразование
...
(7.4) из целочисленного типа или перечислимого типа с незаданной областью в целочисленный тип, который не может представлять все значения исходного типа, , кроме случаев, когда источник является константным выражением, значение которого после интегральных повышений будет соответствовать целевому типу .
. Это дает нам лучшее понимание того, что происходит:
// Works, no narrowing check, implicit conversion.
std::bitset<20> a(2);
std::bitset<20> b(-1);
std::bitset<20> c(cell);
// Works, 2 can be converted without narrowing
std::bitset<20> d{2};
// Fails, -1 cannot be converted without narrowing
std::bitset<20> e{-1};
// Fails, compiler does not understand cell can be converted without narrowing
std::bitset<20> f{cell};
В Ваша программа, компилятор не понимает, что cell
является константным выражением. Он проверяет доступные конструкторы на std::bitset
и видит, что он должен конвертировать из int
в unsigned long long
. Он считает, что int
потенциально может быть отрицательным, поэтому у нас есть сужающееся преобразование.
Мы можем исправить это, сделав cell
a constexpr
, который сильнее const
. Тогда как const
означает только то, что значение не должно изменяться, constexpr
означает, что значение доступно во время компиляции:
constexpr int x = 4;
constexpr int y = 2;
constexpr int cell = x / y;
auto a = std::bitset<20>{cell}; // works
Теперь вы можете спросить, почему инициализация списка не позволяет сужать преобразование. Я не могу полностью ответить на это. Насколько я понимаю, неявное сужение обычно считается нежелательным, поскольку оно может иметь непредвиденные последствия, и что по этой причине оно было исключено.