매개 변수/수정으로 std :: foreach를 사용하는 방법
-
20-08-2019 - |
문제
나는 나 자신이 글을 발견했다
for(int i=0;i<myvec.size();i++)
myvec[i]->DoWhatever(param);
많이, 나는 이것을 foreach
진술, 그러나 어떻게 얻는 지 잘 모르겠습니다 param
슈퍼 비버 보스에 가지 않고 거기에. 나는 또한 같은 것들을 가지고 있습니다
for(int i=0;i<myvec.size();i++)
if(myvec[i]->IsOK())
myvec[i]->DoWhatever(param);
그리고 저도 그 사람을 다시 쓰고 싶습니다. 이견있는 사람?
오, 또한 여러 가지 이유로 부스트를 사용하고 싶지 않습니다.
해결책
#include <vector>
#include <algorithm>
#include <functional>
class X
{
public:
void doWhat(int x) {}
bool IsOK() const {return true;}
};
class CallWhatIfOk
{
public:
CallWhatIfOk(int p): param(p) {}
void operator()(X& x) const
{ if (x.IsOK()) {x.doWhat(param);}}
private:
int param;
};
int main()
{
std::vector<X> myVec;
std::for_each( myVec.begin(),
myVec.end(),
std::bind2nd(std::mem_fun_ref(&X::doWhat),4)
);
std::for_each( myVec.begin(),
myVec.end(),
CallWhatIfOk(4)
);
}
다른 팁
오, 또한 여러 가지 이유로 부스트를 사용하고 싶지 않습니다.
유효한 결정이지만 아마도 잘못된 결정. STL의 확장으로 부스트를 고려하십시오. C ++는 라이브러리 구동 언어입니다. 이것을 고려하지 않으면 코드는 질적으로 열등합니다.
하는 동안 std::for_each
C ++ 0X까지 C ++에 Lambda 표현이 없으면이 지루하게 만들 수 있습니다. 나는 사용을 옹호한다 boost.foreach! 이것은 이것을 만듭니다 많이 더 쉬운 :
foreach (yourtype x, yourvec)
if (x.IsOK())
x.Whatever();
내가 선호하는 솔루션은 일반적으로 내가 필요한 것을 수행하기 위해 untictor를 작성하는 것입니다.
struct doWhatever {
doWhatever(const Param& p) p(p) {}
void operator(MyVec v&, Param p) {
v.DoWhatever(param);
}
private:
Param p;
};
그리고 루프 :
std::for_each(myvec.begin(), myvec.end(), doWhatever(param));
이것의 얼마나 많은 변형에 따라, 이것은 너무 장황 할 수 있습니다. 그래도 인라인을 수행하기위한 많은 옵션이 있습니다. Boost :: Lambda를 사용하면 콜 사이트에서 필요한 기능을 구성 할 수 있습니다. boost :: bind (또는 표준 라이브러리 바인드 함수)를 사용하면 매개 변수를 함수에 바인딩 할 수 있으므로 매번 인수로 제공 할 필요가 없습니다.
Boost :: Lambda는 아마도 가장 간결하고 유연한 접근 방식 일 것입니다. 구문은 기억하기 쉽기 때문에 보통 일반 Functor 접근 방식을 사용합니다. ;)
C ++ 0X Lambda Expresions를 지원하는 컴파일러가 있으면 간단하고 최소 침습적입니다.
std::for_each(myvec.begin(),myvec.end(),[&](X& item){
item->DoWhatever(param);
});
그리고 두 번째 예는 다음과 같이 보일 수 있습니다.
std::for_each(myvec.begin(),myvec.end(),[&](X& item){
if(item->IsOK())
myvec[i]->DoWhatever(param);
});
#include <vector>
#include <algorithm>
#include <boost/bind.hpp>
#include <boost/lambda/if.hpp>
#include <boost/lambda/bind.hpp>
struct A
{
bool IsOK () { return true; }
void DoWhatever (int param) {}
};
struct B
{
bool IsOk (A * a) { return true; }
void DoWhatever (A * a, int param) {}
};
typedef std::vector<A *> Myvec;
void main()
{
Myvec myvec;
int param = 1;
B b;
// first challenge using boost::bind (fnct in the same class)
std::for_each (myvec.begin(), myvec.end(),
boost::bind (&A::DoWhatever, _1, param));
// first challenge using boost::bind (fnct in an external class)
std::for_each (myvec.begin(), myvec.end(),
boost::bind (&B::DoWhatever, &b, _1, param));
// second challange using boost::lambda (fnct in the same class)
std::for_each (myvec.begin(), myvec.end(),
boost::lambda::if_then(
boost::lambda::bind (&A::IsOK, boost::lambda::_1),
boost::lambda::bind (&A::DoWhatever, boost::lambda::_1, param)
)
);
// second challange using boost::lambda (fnct in an external class)
std::for_each (myvec.begin(), myvec.end(),
boost::lambda::if_then(
boost::lambda::bind (&B::IsOK, &b, boost::lambda::_1),
boost::lambda::bind (&B::DoWhatever, &b, boost::lambda::_1, param)
)
);
}
네임 스페이스를 사용하여 단순화 할 수 있습니다 ...
GCC를 사용하는 경우 다음과 같은 것을 정의 할 수 있습니다.
#define foreach(element, array) \
for(typeof((array).begin()) element = (array).begin(), __end_##element = (array).end();\
element != __end_##element;\
++element)
다음과 같이 사용하십시오.
foreach(element, array){
element->DoSomething(); //or (*element)->DoSomething() if type is already a pointer
}
나는 이것을 사용자 정의 배열에서 사용하지만 std :: 벡터에서도 잘 작동합니다.