Было ли предложение добавить std:: bin в стандарт С++?

С++ 14 добавляет возможность использовать бинарные литералы, набрав префикс 0b для значения:

int v = 0b1111; // 15 in decimal

Но для потоков, таких как std::hex или std::oct, нет манипулятора std::bin. Поэтому мне нужно использовать, например. std::bitset для печати:

std::cout << std::bitset<4>(v) << "\n";

Было предложено или рассмотрено? Если да, то какой статус идеи?

Ответ 1

Насколько я знаю, не было предложено добавить флаг форматирования для добавления двоичного форматирования и/или манипулятора std::bin. Вы можете проверить предложения по адресу http://www.open-std.org/jtc1/sc22/wg21/docs/papers/. Я почти уверен, что предложение добавить двоичные литералы не добавило эту возможность (быстрый поиск показал N3472, но я не уверен, является ли это последней версией статьи).

С технической точки зрения это может быть не совсем легко добавить! Все различные флаги обычно хранятся в одном слове в классе потока, и существуют разные причины использовать все биты. Существующие три параметра (std::ios_base::oct, std::ios_base::dec, std::ios_base::hex) могут быть сохранены всего в 2 битах. Конечно, три значения оставят одно значение открытым, за исключением того, что это значение обычно принимается за настройку по умолчанию, то есть не фиксируя базу при чтении. В результате может возникнуть необходимость изменить компоновку классов потока или сделать обработку менее эффективной (например, каким-либо образом используя iword() для хранения дополнительной возможности двоичного форматирования). Я не провел анализ, есть ли реальная проблема с какой-либо из реализаций (я знаю, что нет ни одной для моей реализации, но я действительно использовал все биты в слове, если я правильно помню).

Если вы хотите поддерживать двоичное форматирование, его относительно легко добавить через пользовательский std::num_put<char>. Ниже приведен простой пример. Он не имеет отношения к некоторым параметрам форматирования, которые могут быть желательны, например, к отступам или разделителям цифр:

#include <iostream>
#include <limits>
#include <locale>

class binary_num_put
    : public std::num_put<char> {
    template <typename T>
    iter_type common_put(iter_type out, std::ios_base& str, char_type fill,
                         T original, unsigned long long v) const {
        if (str.flags() & std::ios_base::basefield) {
            return this->std::num_put<char>::do_put(out, str, fill, original);
        }
        if (str.flags() & std::ios_base::showbase) {
            *out++ = '0';
            *out++ = str.flags() & std::ios_base::uppercase? 'B': 'b';
        }
        unsigned long long mask(1ull << (std::numeric_limits<unsigned long long>::digits - 1));
        while (mask && !(mask & v)) {
            mask >>= 1;
        }
        if (mask) {
            for (; mask; mask >>= 1) {
                *out++ = v & mask? '1': '0';
            }
        }
        else {
            *out++ = '0';
        }
        return out;
    }
    iter_type do_put(iter_type out, std::ios_base& str, char_type fill, long v) const {
        return common_put(out, str, fill, v, static_cast<unsigned long>(v));
    }
    iter_type do_put(iter_type out, std::ios_base& str, char_type fill, long long v) const {
        return common_put(out, str, fill, v, static_cast<unsigned long long>(v));
    }
    iter_type do_put(iter_type out, std::ios_base& str, char_type fill, unsigned long v) const {
        return common_put(out, str, fill, v, v);
    }
    iter_type do_put(iter_type out, std::ios_base& str, char_type fill, unsigned long long v) const {
        return common_put(out, str, fill, v, v);
    }
};

std::ostream& bin(std::ostream& out) {
    auto const& facet = std::use_facet<std::num_get<char>>(out.getloc());
    if (!dynamic_cast<binary_num_put const*>(&facet)) {
        std::locale loc(std::locale(), new binary_num_put);
        out.imbue(loc);
    }
    out.setf(std::ios_base::fmtflags(), std::ios_base::basefield);
    return out;
}

int main()
{
    std::cout << std::showbase << bin << 12345 << " "
              << std::dec << 12345 << "\n";
}