Я перегружаю <<
для печати пользовательских объектов (в этом случае экземпляры пользовательского класса Vertex
). Как часть этого, я хочу напечатать данное целое число в двоичном виде. Я предпочел бы по многим причинам std::bitset
вместо того, чтобы запускать цикл for, но проблема, с которой я сталкиваюсь, заключается в том, что у меня есть определенный размер каждого двоичного файла, который зависит от экземпляра. Вот фрагмент:
std::ostream &
operator<< (std::ostream& os, const Vertex& V) {
os << "(" << std::bitset<4>(V.signature()) << ") :";
for (int e=2; e<V.degree(); ++e) {
os << " [" << e << "]=" << V.neighbor(e) << " ";
}
return os;
}
Вместо 4
Я очень хочу поставить size_t
это зависит от V
, Например, вот что я попробовал:
std::ostream &
operator<< (std::ostream& os, const Vertex& V) {
size_t B = V.degree()-1;
os << "(" << std::bitset<B>(V.signature()) << ") :";
for (int e=2; e<V.degree(); ++e) {
os << " [" << e << "]=" << V.neighbor(e) << " ";
}
return os;
}
Ошибка гласит: «Нетипичный аргумент шаблона не является константным выражением». Есть ли способ исправить это без жесткого кодирования параметра? Это не то, что будет известно во время компиляции.
Как насчет простой функции:
string bin_format(int_type value, size_t len);
который вы затем пишете в поток, используя
out << bin_format(v.signature(), v.degree()-1);
Все, что выходит за рамки этого, нарушает принцип KISS и должно быть тщательно обосновано. Например. если вам удастся повторить это так часто, что динамическое распределение в string
вызывает проблемы, вы можете либо написать функцию, принимающую поток и параметры, и записать отдельные биты в поток, либо вы можете вернуть прокси с перегруженным operator<<
где этот оператор выполняет форматирование и потоковую передачу. Кстати, вы могли бы также превратить эту функцию в шаблон, основанный на целочисленном типе, чтобы вы могли по крайней мере поставить максимальное количество нужных вам битов.
Поскольку нет возможности использовать std::bitset<>
с параметром времени выполнения вы, вероятно, должны написать свой собственный класс / функцию, отображающий биты. Вот пример такого класса, который перегружает вставку потока operator<<
:
// Display bits at runtime (cannot use std::bitset<> in this case)
#include <algorithm> // for std::reverse
#include <cstddef> // for std::size_t
#include <iostream>
#include <string>
template<typename T>
class disp_bitset
{
std::size_t _size;
T _n;
public:
explicit disp_bitset(std::size_t size, T n): _size(size), _n(n) {}
friend std::ostream& operator<<(std::ostream& os, const disp_bitset& rhs)
{
T tmp = rhs._n;
std::string aux;
for (std::size_t i = 0; i < rhs._size; ++i)
{
aux += (tmp & 0x01) + '0';
tmp = tmp >> 1;
}
std::reverse(aux.begin(), aux.end());
return os << aux;
}
};
int main()
{
disp_bitset<std::size_t> x(8, 41); // size_t 41 on 8 bits
std::cout << x << std::endl;
std::cout << disp_bitset<char>(16, 'a'); // char 'a' on 16 bits
}
Это полный взлом, так что я надеюсь на что-то лучшее, но, похоже, работа сделана на данный момент. Улучшения приветствуются!
std::ostream &
operator<< (std::ostream& os, const Vertex& V) {
std::string bin = std::bitset<16>(V.signature()).to_string();
bin.erase(bin.begin(),bin.end()-V.degree()+1);
os << "(" << bin << ") :";
for (int e=2; e<V.degree(); ++e) {
os << " [" << e << "]=" << V.neighbor(e) << " ";
}
return os;
}