펑터가 무엇이며 언제 std
알고리즘 과 함께 사용해야하는지 알고 있지만 C ++ 11 FAQ 에서 Stroustrup이 그들에 대해 말하는 것을 이해하지 못했습니다 .
누구든지 무엇이 무엇 std::bind
이고 std::function
언제 사용되어야 하는지 설명하고 초보자를위한 몇 가지 예를 제공 할 수 있습니까?
펑터가 무엇이며 언제 std
알고리즘 과 함께 사용해야하는지 알고 있지만 C ++ 11 FAQ 에서 Stroustrup이 그들에 대해 말하는 것을 이해하지 못했습니다 .
누구든지 무엇이 무엇 std::bind
이고 std::function
언제 사용되어야 하는지 설명하고 초보자를위한 몇 가지 예를 제공 할 수 있습니까?
답변:
std::bind
부분 기능 적용을 위한 것 입니다.
즉, f
3 개의 인수를 받는 함수 객체가 있다고 가정합니다 .
f(a,b,c);
다음과 같이 정의 된 두 개의 인수 만받는 새 함수 객체를 원합니다.
g(a,b) := f(a, 4, b);
g
은 함수의 "부분적 응용"입니다 f
. 중간 인수가 이미 지정되었으며 두 개가 남아 있습니다.
다음 std::bind
을 얻는 데 사용할 수 있습니다 g
.
auto g = bind(f, _1, 4, _2);
이것은 실제로 펑터 클래스를 작성하는 것보다 더 간결합니다.
링크하는 기사에 추가 예제가 있습니다. 일반적으로 일부 알고리즘에 펑터를 전달해야 할 때 사용합니다. 원하는 작업 을 거의 수행하지만 알고리즘이 사용하는 것보다 더 많은 구성 가능 (즉, 더 많은 매개 변수가 있음) 기능 또는 펑터 가 있습니다. 따라서 인수를 일부 매개 변수에 바인딩하고 나머지는 알고리즘이 채울 수 있도록 둡니다.
// raise every value in vec to the power of 7
std::transform(vec.begin(), vec.end(), some_output, std::bind(std::pow, _1, 7));
여기에서 pow
두 개의 매개 변수를 취하고 어떤 거듭 제곱 으로 도 올릴 수 있지만 우리가 신경 쓰는 것은 7 제곱까지 올리는 것뿐입니다.
부분 함수 응용 프로그램이 아닌 가끔 사용하는 경우 bind
인수를 함수에 다시 정렬 할 수도 있습니다.
auto memcpy_with_the_parameters_in_the_right_flipping_order = bind(memcpy, _2, _1, _3);
API가 마음에 들지 않는다고해서 사용하지 않는 것이 좋지만 다음과 같은 이유로 잠재적 인 실용적인 용도가 있습니다.
not2(bind(less<T>, _2, _1));
이 함수는 작거나 같은 함수입니다 (총 주문을 가정하면 어쩌고). 이 예제는 일반적으로 필요하지 않습니다. 이미있는 경우 std::less_equal
( <=
대신 연산자를 사용 <
하므로 일관성이 없으면 이것이 필요할 수 있으며 단서로 클래스 작성자를 방문해야 할 수도 있습니다). 하지만 함수형 프로그래밍을 사용하는 경우 나타나는 일종의 변형입니다.
std::function
어떨까요?
pow
예제는 컴파일되지 않습니다. pow
오버로드 된 함수 이므로 어떤 오버로드를 수동으로 지정해야합니다. 바인딩은 결과 펑터의 호출자가 추론하도록 둘 수 없습니다. 예std::transform(vec.begin(), vec.end(), out.begin(), std::bind((double (*)(double, int))std::pow, _1, 7));
std::bind
함께 제공됩니다 this
. 이 사용 사례를 자세히 설명해 주시겠습니까?
std::placeholders::_1
합니다. 이것이 컴파일되지 않은 이유를 알아내는 데 시간이 걸렸습니다.
std :: function 및 std :: bind의 주요 용도 중 하나는 더 많은 유전자 관련 함수 포인터입니다. 콜백 메커니즘을 구현하는 데 사용할 수 있습니다. 인기있는 시나리오 중 하나는 실행하는 데 오랜 시간이 걸리는 함수가 있지만 반환 될 때까지 기다리지 않고 별도의 스레드에서 해당 함수를 실행하고 함수 포인터를 제공 할 수 있다는 것입니다. 완료 후 콜백.
이를 사용하는 방법에 대한 샘플 코드는 다음과 같습니다.
class MyClass {
private:
//just shorthand to avoid long typing
typedef std::function<void (float result)> TCallback;
//this function takes long time
void longRunningFunction(TCallback callback)
{
//do some long running task
//...
//callback to return result
callback(result);
}
//this function gets called by longRunningFunction after its done
void afterCompleteCallback(float result)
{
std::cout << result;
}
public:
int longRunningFunctionAsync()
{
//create callback - this equivalent of safe function pointer
auto callback = std::bind(&MyClass::afterCompleteCallback,
this, std::placeholders::_1);
//normally you want to start below function on seprate thread,
//but for illustration we will just do simple call
longRunningFunction(callback);
}
};
std :: bind는 부스트 바인드를 포함하도록 제안한 후 라이브러리에 투표되었습니다. 주로 일부 매개 변수를 수정하고 다른 매개 변수를 즉시 변경할 수있는 부분 함수 전문화입니다. 이제 이것은 C ++에서 람다를 수행하는 라이브러리 방식입니다. Steve Jessop의 답변
이제 C ++ 11이 람다 함수를 지원하므로 더 이상 std :: bind를 사용하고 싶은 유혹을 느끼지 않습니다. 나는 도서관 기능보다는 언어 기능이있는 카레 (부분 전문화)를 사용하고 싶다.
std :: function 객체는 다형성 함수입니다. 기본 아이디어는 모든 호출 가능한 객체를 상호 교환 적으로 참조 할 수 있다는 것입니다.
자세한 내용은 다음 두 링크를 알려 드리겠습니다.
C ++ 11의 Lambda 함수 : http://www.nullptr.me/2011/10/12/c11-lambda-having-fun-with-brackets/#.UJmXu8XA9Z8
C ++의 호출 가능 엔티티 : http://www.nullptr.me/2011/05/31/callable-entity/#.UJmXuMXA9Z8
std::bind
람다 없이는 존재하지 않았습니다. 두 기능 모두 C ++ 11에 도입되었습니다. 우리는 있었나요 bind1st
그리고 bind2nd
이는 C ++ (11) 바인딩의 버전을 쇠약 케했다.
나는 C ++에서 플러그인 스레드 풀을 만들기 위해 오랫동안 사용했다. 함수가 세 개의 매개 변수를 취했기 때문에 다음과 같이 작성할 수 있습니다.
메서드에 서명이 있다고 가정합니다.
int CTask::ThreeParameterTask(int par1, int par2, int par3)
세 매개 변수를 바인딩하는 함수 객체를 만들려면 다음과 같이 할 수 있습니다.
// a template class for converting a member function of the type int function(int,int,int)
//to be called as a function object
template<typename _Ret,typename _Class,typename _arg1,typename _arg2,typename _arg3>
class mem_fun3_t
{
public:
explicit mem_fun3_t(_Ret (_Class::*_Pm)(_arg1,_arg2,_arg3))
:m_Ptr(_Pm) //okay here we store the member function pointer for later use
{}
//this operator call comes from the bind method
_Ret operator()(_Class *_P, _arg1 arg1, _arg2 arg2, _arg3 arg3) const
{
return ((_P->*m_Ptr)(arg1,arg2,arg3));
}
private:
_Ret (_Class::*m_Ptr)(_arg1,_arg2,_arg3);// method pointer signature
};
이제 매개 변수를 바인딩하기 위해 바인더 함수를 작성해야합니다. 그래서 여기에 간다 :
template<typename _Func,typename _Ptr,typename _arg1,typename _arg2,typename _arg3>
class binder3
{
public:
//This is the constructor that does the binding part
binder3(_Func fn,_Ptr ptr,_arg1 i,_arg2 j,_arg3 k)
:m_ptr(ptr),m_fn(fn),m1(i),m2(j),m3(k){}
//and this is the function object
void operator()() const
{
m_fn(m_ptr,m1,m2,m3);//that calls the operator
}
private:
_Ptr m_ptr;
_Func m_fn;
_arg1 m1; _arg2 m2; _arg3 m3;
};
그리고 binder3 클래스를 사용하는 도우미 함수-bind3 :
//a helper function to call binder3
template <typename _Func, typename _P1,typename _arg1,typename _arg2,typename _arg3>
binder3<_Func, _P1, _arg1, _arg2, _arg3> bind3(_Func func, _P1 p1,_arg1 i,_arg2 j,_arg3 k)
{
return binder3<_Func, _P1, _arg1, _arg2, _arg3> (func, p1,i,j,k);
}
그리고 여기서 우리는 그것을 부르는 방법
F3 f3 = PluginThreadPool::bind3( PluginThreadPool::mem_fun3(
&CTask::ThreeParameterTask), task1,2122,23 );
참고 : f3 (); task1-> ThreeParameterTask (21,22,23) 메소드를 호출합니다.
자세한 내용은-> http://www.codeproject.com/Articles/26078/AC-Plug-in-ThreadPool-Design
myThread=boost::thread(boost::bind(&MyClass::threadMain, this))