2016-02-28 3 views
2

Предположим, у меня есть вектор символов (или просто пара итераторов), который я хочу напечатать в ostream. Теперь я не просто хочу, чтобы это было напечатано - я хочу, чтобы у него были определенные типы интервалов, я хочу другое представление значений символов, а не просто вычеркивание их на терминал (скажем, как символ, если он доступен для печати, так и экранированный 2 -значное или шестнадцатеричный кодВременно переопределить поведение выходного потока.

Теперь я не хочу, чтобы написать свой собственный код за пределы минимума. - то есть только немного клея и

void foo(ostream& os, char c) { 
    os << c << ' ' << as_hex(c); 
} 

(который, как пользовательские перегрузки для оператора < < без возврата.)

Я не хочу, чтобы нужно было петли над vecotr, и для каждого символа t o вручную вызывать abve, я хочу, чтобы он вел себя и выглядел так, как будто я просто связываю свой вектор с моим потоком outoput, после того как временно изменил атрибуты последнего. Но иногда я хочу, чтобы поток возвращался, чтобы вести себя нормально, даже для одного и того же вектора.

Можно ли это сделать разумно/идиоматично?

ответ

0

Ну, вам нужно написать свой код где-то. Содержимое вашего вектора не будет записываться в std::ostream самостоятельно.

Вы действительно спрашиваете, с какой точки зрения, как использовать оператор << для работы на std::vector<char>. Следующий пример поможет вам начать:

#include <iostream> 
#include <vector> 

std::ostream &operator<<(std::ostream &o, const std::vector<char> &v) 
{ 
    // Fill in the blanks here. 
    return o; 
} 

// Example: 

int main() 
{ 
    std::vector<char> v; 

    std::cout << v; 

    return 0; 
} 
1

Я предполагаю, что вы знаете о перегрузке операторов и ваша главная проблема заключается в том, как сказать оператору, какой вариант форматирования использовать, т.е. как хранить произвольную информацию в потоке.

Все, что происходит от std::ios_base (всех стандартных классов потока) имеет .iword() метод, который возвращает ссылку на long из некоторых внутренней памяти и .pword(), который возвращает ссылку на void*. Уникальный индекс для этих вызовов может быть Изучаются через вызов std::ios_base::xalloc()

Примера использования запоминаните поток, чтобы изменить поведение операции вывода:

#include <iostream> 
#include <vector> 

const int vprint_index = std::ios_base::xalloc(); 

std::ostream& operator<<(std::ostream& out, std::vector<char> vec) 
{ 
    if (out.iword(vprint_index) == 0) { 
     for(char c: vec) 
      out << c; 
     return out; 
    } 
    out.iword(vprint_index) = 0; 
    out << '{'; 
    bool first = true; 
    for(char c: vec) { 
     if(!first) 
      out << ", "; 
     first = false; 
     out << c; 
    } 
    return out << '}'; 
} 

int main() 
{ 
    std::vector<char> vector {'f', 'o', 'o'}; 
    std::cout << vector << '\n'; 
    std::cout.iword(vprint_index) = 1; 
    std::cout << vector << '\n'; 
    std::cout << vector << '\n'; 
} 

Foo
{F, O, O}
Foo

+0

Это не делает трюк, так как мне нужно перегрузки быть * временный * - Мне нужно, чтобы иметь возможность его включения или выключения , – einpoklum

+0

@einpoklum Добавьте 'std :: cout.iword (vprint_index) = 0;' после этого. Если вам нужно, чтобы он работал только на одной операции (нелипкий манипулятор), попросите оператора очистить его сам. –

+0

@Revolver_Ocelot «временное переопределение» форматирования потока может означать одну из двух вещей: либо серию одноразовых манипуляций (где поток автоматически возвращается после каждого вызова - моя интерпретация), либо изменение состояния (видимо, ваше). Я отвечаю на ваш ответ, поскольку он правильно находит место для хранения состояния (для последней интерпретации). Поскольку вопрос плохо сформулирован и неясен, невозможно установить первоначальное намерение (и это не имеет большого значения). –

1

Для перегрузки, чтобы быть временным, я подумал, что было бы неплохо сделать некоторые вещи, как в iomanip , Это позволит сделать такие вещи, как

int main() 
{ 
    std::vector<char> v{'a', 'b'}; 
    /* v should be printed using foo_vector_print, perhaps 
    * next invocation should use a different format. */ 
    std::cout << foo_vector_print() << v << std::endl; 
} 

Идея заключается в том, чтобы иметь что-то вида:

stream << manip << vector; 

где

  • stream << manip возвращает объект класса, хранящий ссылку поток.
  • ... << vector будет печатать в определенном формате, а затем возвращать ссылку на исходный поток.

Следующая программа показывает, как это сделать:

#include <iostream> 
#include <vector> 


namespace detail 
{ 

// A dummy class in detail namespace, simply records the original ostream object. 
struct foo_vector_printer_imp 
{ 
    std::ostream *m_os; 
}; 

}; 


// This particular implementation simply prints out the vectors size. 
std::ostream &operator<<(detail::foo_vector_printer_imp imp, const std::vector<char> &v) 
{ 
    *imp.m_os << v.size(); 

    return *imp.m_os; 
} 


struct foo_vector_print{}; 


/* The result of piping a foo_vector_print into an ostream, 
* is a foo_vector_printer_imp object recording the ostream */ 
detail::foo_vector_printer_imp operator<<(std::ostream &os, const foo_vector_print &) 
{ 
    detail::foo_vector_printer_imp imp; 
    imp.m_os = &os; 
    return imp; 
} 


int main() 
{ 
    std::vector<char> v{'a', 'b'}; 
    std::cout << foo_vector_print() << v << std::endl; 
} 
+0

Как работает метод 'setw()'? – einpoklum

+0

Я бы предположил, что 'setw' проще, поскольку он просто ссылается на поток, называет его метод и возвращает ссылку на тот же объект. Ответ выше возвращает другой объект другому классу, «толкающему» исходный поток, затем следующий «<<' »выдает« исходный поток ». –

+0

@einpoklum Вы можете называть 'setw' и выводить свои данные в двух разных выражениях. Там вам нужно связаться с вашими операторами. Это немного отличается, но в большинстве случаев это не заметно. –

Смежные вопросы