2009-04-02 6 views
4

내가이C++ 표준 : : 변환 부작용

struct Converter 
{ 
    Converter(std::size_t value): 
     value_(value), i_(0) 
    {} 
    std::string operator() (const std::string& word) 
    { 
     return (value_ & (1 << i_++)) ? 
      word: 
      std::string(word.size(), ' '); 
    } 
    std::size_t value_; 
    std::size_t i_; 
}; 

처럼 UnaryOperation의 구현을했습니다 그리고 내가

std::vector v; 
// initialization of v 
std::transform(v.begin(), v.end(), 
       std::back_inserter(result), 
       Converter(data)); 

질문처럼 사용하는 것은 내 가정, 그 알고리즘에 의존 할 수있다 'Converter :: i_'가 'v'의 요소 수에 해당하는 순서로 'Converter operator()'를 호출합니다.

주문에 의지 할 수 없거나 문제가 발생할 수있는 문제가 발생하지 않도록 stl과 같은 해결책을 제시 할 수 없으므로 표준을 인용하십시오.

감사합니다.

편집 :

내가 변환 알고리즘의 표준에 "아니오 부작용"요구 사항을 알고 있습니다. 동일한 표준의 펑터에 대해 정확히 "부작용"을 찾을 수 없습니다.

어쩌면이 작업을위한 훌륭한 솔루션이 있을까요?

+0

사실 실제로 부작용에 대한 메모는 현재 초안에 나타나지 않습니다. 대신 알고리즘은 달리 명시하지 않는 한 함수 객체를 자유롭게 복사 할 수 있다고 말합니다. 그래서 "부작용"은 함수 객체의 멤버를 수정한다는 의미입니다. –

답변

6

명 Qute :

25.2.3이 [lib.alg 변환.변환]
요구 사항 :
op 및 binary_op에는 부작용이 없어야합니다. 귀하의 경우에는 Side Effect (wikipedia definition)

우리는 다음의 부작용이 있습니다

Converter c(data); 
c(some_const_value) != c(some_const_value); 

당신은 당신의 알고리즘에 대한 어떤 보장이없는,하지만 난 것이다 거의 모든 STL과 구현에 작동하는지 보라 .

제안 된 해결 당신이 무엇을해야하는 한 가지 방법을 알 것 같다
:
사용 부스트 :: counting_iterator을 - 두 개의 컨테이너에 걸쳐 반복 처리를 위해; 당신이 비트 반복자를 정의 할 것이다 또는 반복 처리 모두 용기를 약간 비트는 부스트 사용할 수있는 것 용기 :: zip_iterator을 사용할 경우 어쩌면 또한

bool bit_enabled(size_t data, unsigned char number) 
{ 
    return (data & 1 << number) != 0; 
} 

std::string select_word( 
       const std::string& word, 
       size_t data, 
       size_t number) 
{ 
    return bit_enabled(data, number) ? word : std::string(' ', word.length()); 
} 

const size_t data = 7; 
const boost::array< std::string, 3 > vocabulary = { "a", "b", "c" }; 
std::vector<std::string> result; 
std::transform(
    vocabulary.begin(), 
    vocabulary.end(), 
    boost::counting_iterator<size_t>(0), 
    back_inserter(result), 
    boost::bind(&select_word, _1, data, _2) 
); 

: 그것은 것

는 것 같습니다.

편집 :
Yestarday 나는 표준에 의해 부작용의 정의가 포함 interest article 발견했다. 다음과 같이

표준은 부작용을 정의하고, 물체를 변형 휘발성 좌변, 의해 지정된 객체 액세스 라이브러리 I/O 기능을 호출하거나, 이들 중 하나를 수행하는 기능 호출 작업은 모든 부작용입니다. 의 실행 상태는 입니다.

편집 :
나는 그것이 최신 편집이 되길 바랍니다.
나는 항상 "부작용이 없다"는 뜻입니다 :
f (a)는 항상 f (a)와 같아야합니다. (실행 환경으로부터 독립된 f : 메모리/cpu/전역 변수/멤버 변수 등).
"부작용이 없음"의미 - 실행 환경이 변경되지 않습니다.

하지만 C++ 표준에서는 부작용에 대한 더 낮은 수준의 정의가 있습니다.

예에서 수행하는 작업은 으로되어 있습니다. 상태 유지 functor.
Standard는 "Statefull"펑터에 대해 말하지 않지만 functor 사본의 수에 대해서도 말하지 않습니다. 이것은 명시되지 않은 동작이므로이 트릭을 사용할 수 없습니다.

참조 표준 라이브러리 문제 목록 (predicat에 대한 유사한 문제) : 나는 대답이 '예'어떤 경우가 생각하지만, 그것은 더의 명확한 경우도 있습니다
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#92

+0

"부작용"에 대한 설명 주셔서 감사합니다. –

+0

좋은 카운 터 _iterator! 변환은 두 개의 컨테이너를 사용할 수 있습니다. 솔루션을 다시 한번 변경 하시겠습니까? –

+0

나는 또한 부작용의 정의를 고려했다. 그러나이 맥락에서 어떤 의미가 없습니다. operator()에서이 일을한다고 상상해보십시오 : {int a; a = 4; return T (t, a); }는 부작용 (지역 변수 "a"수정)이 될 것이므로 transform의 스펙에 의해 허용되지 않습니다. –

0

예 아니요. 이는 반복자를 Converter 개체에 공급하기 때문입니다. vector과 같은 시퀀스 컨테이너의 경우 요소 순서에 따라 i이 표시됩니다. 그러나 연관 컨테이너의 경우 map/multimap/set/multiset과 같이 유효하지 않을 수도 있습니다.

+0

집합을위한 알고리즘은 여전히 ​​새로운 항목을 추가하기 위해 출력 반복자를 사용합니다. 그래서 그것은 하나를 취해 출력으로 밀어 넣습니다. 나는 "UnaryOperation에는 어떠한 부작용도 없어야한다"는 것에 대해 의구심을 품는다. –

2

방금 ​​표준을 확인한 결과 제대로 이해하면 대답은 '아니오'입니다. OP와 binary_op 어떤 부작용이 없다 :

가 : '변환'의 설명은 다음의 추가 조건 (25.2.3)를 갖는다.

내 기억의 깊이에 다시 도달, 나는 그가 용기와 STL 구현의 특정 유형, 함수 객체가 복사 된 것을 보여 주었다 ACCU 회의에서 Nicolai Josuttis 주어진 이야기를 기억한다. Éricthis으로 제공됩니다. 자세한 내용은 차이점을 설명하는 Dr. Dobb의 기사를 참조하십시오.

편집 : 대체 솔루션 : 당신이 결과 벡터에 대한 참조를 가지고 컨버터 기능 내부와 push_back을 위해 변환기 개체를 변경할 수 있도록

의 for_each 알고리즘은,이 제한이 없습니다.

struct Converter 
{ 
    Converter(std::size_t value, std::vector<std::string> & result): 
     value_(value), i_(0), result_(result) 
    {} 
    void operator() (const std::string& word) 
    { 
    result_.push_back (value_ & (1 << i_++)) ? 
      word: 
      std::string(word.size(), ' '); 
    } 
    std::size_t value_; 
    std::size_t i_; 
    std::vector<std::string> & result_; 
}; 

그리고 의 for_each보다는 변환 사용 표준에서

std::vector v; 
// initialization of v 
std::for_each (v.begin() 
       , v.end(), 
       Converter(data, result)); 
+0

부작용에 대해 설명해 주셔서 감사합니다. –

+0

"실제로 이것이 의미 할 수 있다고 생각합니다 ..."내가 이걸 증명할 수있는 곳은 어디입니까? –

+0

Erm .... 잘 - 저는 Nicolai Josuttis가 실제 코드 예제로 이야기 한 Oxford의 ACCU 회의에 참석 한 후에 만이 사실을 알 수 있습니다. 빠른 google 검색 결과는 다음과 같습니다. http://learningcppisfun.blogspot.com/2007/02/i-was-discussing-about-problem-here.html –

0

.어떤 것을 (유감스럽게 생각하는지) 기억할 필요가없고, 코드를 덜 부서지기 쉽도록 만들지 않고, 나는 그것에 의지하지 않고 안전을 위해 저의 펑터 밖에서 계속 지키지 않을 것입니다. Converter 내부 즉 수행

Converter(std::size_t value, std::size_t& i): value_(value), i_ (i) {}
std::size_t &i_;


는 호출

std::vector v;
std::size_t i(0);
// initialization of v
std::transform(v.begin(), v.end(), std::back_inserter(result), Converter(data, i));

지저분하지만 안전과.

1

부작용이 확실한 인 경우의 예로서이라는 나쁜 점이 있다면 여러 CPU간에 작업을 분할하는 가상의 병렬 STL 구현을 고려하십시오.

나는 이것이 STL의 저자 마음에 있다고 생각한다. 원래 STL은 대규모 병렬 단일 이미지 및 클러스터 시스템 구축에있어 큰 이름 중 하나 인 SGI에서 나왔습니다.

+0

"병렬 STL"에 대한 흥미로운 추측. 증거가 필요해. 복사 또는 무언가에 관하여 기준에서 인용하십시오. –