Шаблон класса Стандартная библиотека std::bitset<N>
имеет конструктор (C ++ 11 и далее, unsigned long
аргумент перед C ++ 11)
constexpr bitset(unsigned long long) noexcept
Вопреки многим рекомендациям, этот конструктор с одним аргументом не помечен как explicit
, В чем причина этого?
Основное возражение против explicit
Конструктор заключается в том, что инициализация копирования из целых чисел без знака больше не работает
constexpr auto N = 64;
std::bitset<N> b(0xDEADC0DE); // OK, direct initialization
std::bitset<N> b = 0xDEADC0DE; // ERROR, copy initialization cannot use explicit constructors
поскольку std::bitset<N>
подразумевается как обобщение unsigned int
конструктор, вероятно, был сделан неявным, чтобы облегчить адаптацию существующего кода в стиле C в стиле bit-twiddling на основе raw unsigned int
, Создание конструктора explicit
сломал бы много существующего кода (и добавление его теперь также сломало бы существующий код).
ОБНОВИТЬ: занимаясь стандартной археологией, я нашел N0624 с января 1995 года, который предложил добавить новое ключевое слово тогда explicit
ко всем конструкторам с одним аргументом в предварительном проекте библиотеки. Это было поставлено на голосование на собрании в марте 1995 года (Остин). Как указано в N0661, unsigned long
конструктор для bitset
не было сделано explicit
(единогласно, но без мотивации).
Тем не менее, даже если bitset
легко инициализируется из unsigned long
, в противном случае есть неполные операции по установке смешанного режима (&
, |
или же ^
):
constexpr auto N = 512;
std::bitset<N> b = 0xDEADC0DE; // OK
std::bitset<N> c = b & 0xFFFF; // ERROR, cannot deduce template arguments for rhs
Это можно исправить, предложив перегруженные операторы для поддержки смешанного режима смешанного режима:
// @ from { &, |, ^ }
template<std::size_t N>
bitset<N> operator@(unsigned long long lhs, const bitset<N>& rhs)
template<std::size_t N>
bitset<N> operator@(const bitset<N>& lhs, unsigned long long rhs)
Шизофреническая природа std::bitset
относительно функциональности смешанного режима также присутствует в operator==
а также operator!=
, Это функции-члены, которые имеют неявное преобразование в своих аргументах rhs, но не в своих аргументах lhs ( this
указатель, который подлежит удержанию аргумента шаблона). Это приводит к следующему:
#include <bitset>
#include <iostream>
int main()
{
constexpr auto N = 64;
constexpr std::bitset<N> b = 0xDEADC0DE; // OK, copy initialization
std::cout << (b == 0xDEADC0DE); // OK, implicit conversion on rhs
std::cout << (0xDEADC0DE == b); // ERROR, no implicit conversion on lhs
}
Истоки этого поведения вытекают из предложения 1992 года N0128. Время этого предложения, которое во многом зависело от функциональности будущего std::bitset
, был до шаблонов функций, имеющих нетипизированные параметры шаблона. Единственный возможный обходной путь в то время состоял в том, чтобы сделать все перегруженные операторы функциями-членами вместо функций, не являющихся членами. Это никогда не изменилось позже, когда стали доступны более продвинутые технологии шаблонов (см. Также этот вопрос& почему это может нарушить код).