어떤 iomanip 조작자가 '고정적'입니까?


140

최근에 명시 적으로 변경할 때까지 모든 삽입에 대해 문자열 스트림에 stringstream잘못 std::setw()영향을 줄 것이라고 가정했기 때문에 최근에 문제를 일으키는 데 문제가있었습니다 . 그러나 삽입 후에는 항상 설정 해제됩니다.

// With timestruct with value of 'Oct 7 9:04 AM'
std::stringstream ss;
ss.fill('0'); ss.setf(ios::right, ios::adjustfield);
ss << setw(2) << timestruct.tm_mday;
ss << timestruct.tm_hour;
ss << timestruct.tm_min;
std::string filingTime = ss.str(); // BAD: '0794'

그래서 많은 질문이 있습니다.

  • setw()이런 식입니까?
  • 다른 조작자가 이런 식으로 있습니까?
  • std::ios_base::width()과 (와)의 동작에 차이가 std::setw()있습니까?
  • 마지막으로이 동작을 명확하게 문서화 한 온라인 참조가 있습니까? 내 공급 업체 설명서 (MS Visual Studio 2005)에이를 명확하게 표시하지 않는 것 같습니다.

작업 라운드는 여기에 있습니다 : stackoverflow.com/a/37495361/984471
Manohar Reddy Poreddy

답변:


87

아래 의견의 중요 사항 :

마틴

@Chareles : 그런 다음이 요구 사항에 따라 모든 조작자가 끈적 거리게됩니다. 사용 후 리셋 된 것으로 보이는 setw를 제외하고.

찰스

바로 그거죠! setw가 다르게 동작하는 유일한 이유는 출력 스트림을 명시 적으로 .width (0)하기위한 형식화 된 출력 작업에 대한 요구 사항이 있기 때문입니다.

다음은 위의 결론으로 ​​이어지는 논의입니다.


다음 조작자는 코드를 보면 스트림이 아닌 객체를 반환합니다.

setiosflags
resetiosflags
setbase
setfill
setprecision
setw

이것은 스트림에 적용되는 다음 객체에만 작업을 적용하는 일반적인 기술입니다. 불행히도 이것은 끈적 거리는 것을 배제하지 않습니다. 테스트 결과를 제외하고 setw는 모두 끈적임을 나타냅니다 .

setiosflags:  Sticky
resetiosflags:Sticky
setbase:      Sticky
setfill:      Sticky
setprecision: Sticky

다른 모든 조작자는 스트림 객체를 반환합니다. 따라서 그들이 변경 한 상태 정보는 스트림 객체에 기록되어야하며 따라서 다른 조작자가 상태를 변경할 때까지 영구적입니다. 따라서 다음 조작기는 고정 조작 이어야합니다 .

[no]boolalpha
[no]showbase
[no]showpoint
[no]showpos
[no]skipws
[no]unitbuf
[no]uppercase

dec/ hex/ oct

fixed/ scientific

internal/ left/ right

이 조작자는 실제로 스트림 객체가 아닌 스트림 자체에서 작업을 수행합니다 (기술적으로 스트림은 스트림 객체 상태의 일부 임). 그러나 스트림 개체 상태의 다른 부분에는 영향을 미치지 않습니다.

ws/ endl/ ends/ flush

결론은 setw가 내 버전에서 끈적 거리지 않는 유일한 조작자 인 것 같습니다.

Charles에게 체인의 다음 항목에만 영향을 미치는 간단한 트릭 :
다음은 오브젝트를 사용하여 일시적으로 상태를 변경하고 오브젝트를 사용하여 상태를 되돌릴 수있는 예제입니다.

#include <iostream>
#include <iomanip>

// Private object constructed by the format object PutSquareBracket
struct SquareBracktAroundNextItem
{
    SquareBracktAroundNextItem(std::ostream& str)
        :m_str(str)
    {}
    std::ostream& m_str;
};

// New Format Object
struct PutSquareBracket
{};

// Format object passed to stream.
// All it does is return an object that can maintain state away from the
// stream object (so that it is not STICKY)
SquareBracktAroundNextItem operator<<(std::ostream& str,PutSquareBracket const& data)
{
    return SquareBracktAroundNextItem(str);
}

// The Non Sticky formatting.
// Here we temporariy set formating to fixed with a precision of 10.
// After the next value is printed we return the stream to the original state
// Then return the stream for normal processing.
template<typename T>
std::ostream& operator<<(SquareBracktAroundNextItem const& bracket,T const& data)
{
    std::ios_base::fmtflags flags               = bracket.m_str.flags();
    std::streamsize         currentPrecision    = bracket.m_str.precision();

    bracket.m_str << '[' << std::fixed << std::setprecision(10) << data << std::setprecision(currentPrecision) << ']';

    bracket.m_str.flags(flags);

    return bracket.m_str;
}


int main()
{

    std::cout << 5.34 << "\n"                        // Before 
              << PutSquareBracket() << 5.34 << "\n"  // Temp change settings.
              << 5.34 << "\n";                       // After
}


> ./a.out 
5.34
[5.3400000000]
5.34

좋은 치트 시트. 정보의 출처에 대한 참조를 추가하면 완벽한 답변이 될 것입니다.
Mark Ransom

1
그러나 setfill ()이 객체를 반환하지만 실제로 'sticky'인지 확인할 수 있습니다. 그래서 나는이 대답이 옳지 않다고 생각합니다.
John K

2
스트림을 반환 객체는 반드시 객체를 반환하는 사람들은 끈적 될 수 있지만, 끈적하지만 필요하지 않습니다. John 's Info로 답변을 업데이트하겠습니다.
Martin York

1
나는 당신의 추론을 이해하지 못할 것입니다. 매개 변수를 사용하는 모든 조작자는 해당 개체가 스트림에 삽입 될 때 스트림에 작용하는 지정되지 않은 개체를 반환하는 자유 함수로 구현되며 이는 매개 변수를 사용하여 삽입 구문을 유지하는 유일한 방법입니다. 어느 쪽이든, operator<<조작자에 적합 하면 스트림 상태가 특정 방식으로 변경됩니다. 어느 형태도 어떤 종류의 상태 보초도 설정하지 않습니다. 상태의 어떤 부분이 재설정되는지 결정하는 것은 다음 형식의 삽입 작업의 동작입니다.
CB Bailey

3
바로 그거죠! setw다르게 동작 하는 유일한 이유 .width(0)는 출력 스트림 을 명시 적으로 지정하기 위해 형식화 된 출력 조작에 대한 요구 사항이 있기 때문 입니다.
CB Bailey

31

width'고정적'으로 보이지 않는 이유 는 특정 작업이 .width(0)출력 스트림 을 호출하도록 보장하기 때문 입니다. 사람들은:

21.3.7.9 [lib.string.io] :

template<class charT, class traits, class Allocator>
  basic_ostream<charT, traits>&
    operator<<(basic_ostream<charT, traits>& os,
               const basic_string<charT,traits,Allocator>& str);

22.2.2.2.2 [lib.facet.num.put.virtuals] : 템플릿에 do_put대한 모든 과부하 num_put. 이것들은 operator<<a basic_ostream및 내장 숫자 유형의 과부하로 사용됩니다 .

22.2.6.2.2 [lib.locale.money.put.virtuals] : 템플릿에 do_put대한 모든 과부하 money_put.

27.6.2.5.4 [lib.ostream.inserters.character]의 과부하 operator<<복용하는 basic_ostream과 문자 상기 basic_ostream 인스턴스화의 유형 또는 중 하나 char에 서명 char하거나 unsigned char또는 포인터 이러한 문자 유형의 배열에 있습니다.

솔직히 말해서 나는 이것에 대한 이론적 근거는 확실하지 않지만 ostream형식화 된 출력 함수로 다른 상태를 재설정해서는 안됩니다. 물론, 출력 작업에 오류가있는 경우 badbit와 같 거나 failbit설정 될 수 있지만 예상해야합니다.

너비를 재설정 할 때 생각할 수있는 유일한 이유는 일부 구분 된 필드를 출력하려고 할 때 구분 기호가 채워져 있으면 놀라 울 수 있기 때문입니다.

예 :

std::cout << std::setw(6) << 4.5 << '|' << 3.6 << '\n';

"   4.5     |   3.6      \n"

'수정'하려면 다음이 필요합니다.

std::cout << std::setw(6) << 4.5 << std::setw(0) << '|' << std::setw(6) << 3.6 << std::setw(0) << '\n';

폭을 재설정하면 원하는 출력을 더 짧게 생성 할 수 있습니다.

std::cout << std::setw(6) << 4.5 << '|' << std::setw(6) << 3.6 << '\n';

6

setw()다음 삽입에만 영향을 미칩니다. 그것은 단지 setw()행동 하는 방식 입니다. 의 동작은와 setw()동일합니다 ios_base::width(). cplusplus.comsetw() 에서 내 정보를 얻었습니다 .

여기 에서 전체 조작기 목록을 찾을 수 있습니다 . 해당 링크에서 모든 스트림 플래그는 다른 조작자가 변경 될 때까지 설정되어야합니다. 하나는 대한주의 left, rightinternal조작기가 : 그들은 다른 플래그와 같이하고 않는 변경 될 때까지 유지됩니다. 그러나 스트림의 너비를 설정 한 경우에만 효과가 있으며 너비는 모든 줄마다 설정해야합니다. 예를 들어

cout.width(6);
cout << right << "a" << endl;
cout.width(6);
cout << "b" << endl;
cout.width(6);
cout << "c" << endl;

너에게 줄거야

>     a
>     b
>     c

그러나

cout.width(6);
cout << right << "a" << endl;
cout << "b" << endl;
cout << "c" << endl;

너에게 줄거야

>     a
>b
>c

입력 및 출력 조작기는 고정되어 있지 않으며 사용 된 위치에서 한 번만 발생합니다. 매개 변수화 된 조작자는 각각 다릅니다. 여기에 각각에 대한 간단한 설명이 있습니다.

setiosflags플래그를 수동으로 설정할 수 있습니다 . 에서 끈적입니다.

resetiosflags ~와 비슷한 동작 setiosflags지정된 플래그를 설정 해제한다는 점 제외하고 .

setbase 스트림에 삽입 된 정수의 밑을 설정합니다 (따라서 밑 16의 17은 "11", 밑 2는 "10001").

setfillsetw사용될 때 채우기 문자를 스트림에 삽입하도록 설정합니다 .

setprecision 부동 소수점 값을 삽입 할 때 사용할 소수 자릿수를 설정합니다.

setw 에 지정된 문자로 채워서 다음 삽입 만 지정된 너비로 만듭니다. setfill


글쎄, 그들 대부분은 단지 플래그를 설정하기 때문에 "끈적"입니다. setw ()는 하나의 삽입에만 영향을 미치는 유일한 것으로 보입니다. cplusplus.com/reference/iostream/manipulators
David Brown

그럼 std::hex끈적하지 않고, 분명, std::flush또는 std::setiosflags중 하나 끈적하지 않습니다. 그래서 그렇게 간단하지 않다고 생각합니다.
sbi

16 진수와 setiosflags ()를 테스트하기 만하면 둘 다 고정 된 것처럼 보입니다 (두 개 모두 변경 될 때까지 해당 스트림에 대해 지속되는 플래그를 설정합니다).
David Brown

예, std::hex끈적 거리지 않다고 주장하는 웹 페이지 가 잘못되었습니다. 나도 이것을 발견했습니다. 그러나 스트림 플래그는 std::setiosflags다시 삽입하지 않아도 변경 될 수 있으므로이를 끈적 거리지 않은 것으로 볼 수 있습니다. 또한 std::ws끈적 거리지 않습니다. 그래서 입니다 하지 쉬운.
sbi

답변을 개선하기 위해 많은 노력을 기울였습니다. +1
sbi 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.