C ++ 14에서 람다를 통해 std :: bind를 사용하는 이유는 무엇입니까?
11 ++ C 전에 내가 사용 boost::bind
또는 boost::lambda
많이. 이 bind
부분은 표준 라이브러리 ( std::bind
) 로 만들었고 다른 부분은 핵심 언어 (C ++ 람다)의 일부가되었고 람다 사용을 훨씬 더 쉽게 만들었습니다. 요즘에는 std::bind
C ++ 람다로 거의 모든 것을 할 수 있기 때문에 거의 사용 하지 않습니다. std::bind
내가 생각할 수있는 유효한 사용 사례가 하나 있습니다.
struct foo
{
template < typename A, typename B >
void operator()(A a, B b)
{
cout << a << ' ' << b;
}
};
auto f = bind(foo(), _1, _2);
f( "test", 1.2f ); // will print "test 1.2"
이에 해당하는 C ++ 14는 다음과 같습니다.
auto f = []( auto a, auto b ){ cout << a << ' ' << b; }
f( "test", 1.2f ); // will print "test 1.2"
훨씬 짧고 간결합니다. (C ++ 11에서는 자동 매개 변수로 인해 아직 작동하지 않습니다.) std::bind
C ++ 람다 대안 을 이기는 다른 유효한 사용 사례 가 std::bind
있습니까? 아니면 C ++ 14에 불필요합니까?
Scott Meyers가 이에 대해 이야기 했습니다. 이것이 내가 기억하는 것입니다.
C ++ 14에는 람다로도 할 수없는 유용한 바인드가 없습니다.
그러나 C ++ 11 에서는 람다로 수행 할 수없는 몇 가지 작업이 있습니다.
람다를 만들 때 캡처하는 동안 변수를 이동할 수 없습니다. 변수는 항상 lvalue로 캡처됩니다. 바인드의 경우 다음과 같이 작성할 수 있습니다.
auto f1 = std::bind(f, 42, _1, std::move(v));
식은 캡처 할 수 없으며 식별자 만 캡처 할 수 있습니다. 바인드의 경우 다음과 같이 작성할 수 있습니다.
auto f1 = std::bind(f, 42, _1, a + b);
함수 개체에 대한 인수 오버로딩. 이것은 이미 질문에서 언급되었습니다.
- 완벽하게 전진하는 것은 불가능하다
C ++ 14 에서는 이 모든 것이 가능합니다.
이동 예 :
auto f1 = [v = std::move(v)](auto arg) { f(42, arg, std::move(v)); };
식 예 :
auto f1 = [sum = a + b](auto arg) { f(42, arg, sum); };
질문보기
완벽한 전달 : 당신은 쓸 수 있습니다
auto f1 = [=](auto&& arg) { f(42, std::forward<decltype(arg)>(arg)); };
바인딩의 몇 가지 단점 :
바인딩은 이름으로 바인딩하므로 결과적으로 동일한 이름 (오버로드 된 함수)을 가진 여러 함수가있는 경우 bind는 사용할 함수를 알지 못합니다. 다음 예제는 컴파일되지 않지만 람다는 문제가 없습니다.
void f(int); void f(char); auto f1 = std::bind(f, _1, 42);
- 바인드 함수를 사용할 때 인라인 될 가능성이 적습니다.
반면에 람다는 이론적으로 bind보다 더 많은 템플릿 코드를 생성 할 수 있습니다. 각 람다에 대해 고유 한 유형을 얻습니다. bind의 경우 다른 인수 유형과 다른 함수가있을 때만 발생합니다 (실제로 동일한 인수와 함수로 여러 번 바인딩하는 경우는 자주 발생하지 않습니다).
Jonathan Wakely가 그의 답변에서 언급 한 것은 실제로 bind를 사용하지 않는 또 다른 이유입니다. 나는 당신이 왜 조용히 논쟁을 무시하고 싶은지 알 수 없습니다.
std::bind
다형성 람다가 할 수없는 일을 여전히 할 수 있습니다 : 오버로드 된 함수 호출
struct F {
bool operator()(char, int);
std::string operator()(char, char);
};
auto f = std::bind(F(), 'a', std::placeholders::_1);
bool b = f(1);
std::string s = f('b');
bind 식에 의해 생성 된 호출 래퍼는 제공하는 인수에 따라 다른 함수를 호출하고 C ++ 14 다형성 람다의 클로저는 다른 유형 의 인수를 사용할 수 있지만 다른 수 의 인수를 사용할 수 없으며 항상 ( 전문화) 클로저에 대한 동일한 기능. 수정 : 아래 설명 참조
에서 반환 된 래퍼는 너무 많은 인수를 사용하여 std::bind
호출 할 수도 있으며 무시할 수 있지만 람다에 의해 생성 된 클로저는 너무 많은 인수를 전달하려는 시도를 진단합니다 ...하지만 이점은 고려하지 않습니다. :)std::bind
For me, a valid use for std::bind
is to make it clear that I'm using a member function as a predicate. That is, if all I do is call a member function, it's bind. If I do extra stuff with the argument (besides calling a memeber function), it's a lambda:
using namespace std;
auto is_empty = bind(&string::empty, placeholders::_1); // bind = just map member
vector<string> strings;
auto first_empty = any_of(strings.begin(), strings.end(), is_empty);
auto print_non_empty = [](const string& s) { // lambda = more than member
if(s.empty()) // more than calling empty
std::cout << "[EMPTY]"; // more than calling empty
else // more than calling empty
std::cout << s; // more than calling empty
};
vector<string> strings;
for_each(strings.begin(), strings.end(), print_non_empty);
Sometimes it is just less code. Consider this:
bool check(int arg1, int arg2, int arg3)
{
return ....;
}
Then
wait(std::bind(check,a,b,c));
vs lambda
wait([&](){return check(a,b,c);});
I think that bind is easier to read here compared to the lambda which looks like a https://en.wikipedia.org/wiki/Brainfuck
Another difference is that arguments to bind must be copied or moved, while a lambda can use variables captured by reference. See example below:
#include <iostream>
#include <memory>
void p(const int& i) {
std::cout << i << '\n';
}
int main()
{
std::unique_ptr<int> f = std::make_unique<int>(3);
// Direct
p(*f);
// Lambda ( ownership of f can stay in main )
auto lp = [&f](){p(*f);};
lp();
// Bind ( does not compile - the arguments to bind are copied or moved)
auto bp = std::bind(p, *f, std::placeholders::_1);
bp();
}
Not sure if it's possible to workaround the issue to use bind above without changing the signature of void p(const int&)
.
Just expanding @BertR's comment to this answer to something testable, though I confess I couldn't quite get a solution using std::forward<> to work.
#include <string>
#include <functional>
using namespace std::string_literals;
struct F {
bool operator()(char c, int i) { return c == i; };
std::string operator()(char c, char d) { return ""s + d; };
};
void test() {
{ // using std::bind
auto f = std::bind(F(), 'a', std::placeholders::_1);
auto b = f(1);
auto s = f('b');
}
{ // using lambda with parameter pack
auto x = [](auto... args) { return F()('a', args...); };
auto b = x(1);
auto s = x('b');
}
}
Test at Compiler Explorer
ReferenceURL : https://stackoverflow.com/questions/17363003/why-use-stdbind-over-lambdas-in-c14
'UFO ET IT' 카테고리의 다른 글
새로운 JSLint 오류 "탭이 아닌 공백 사용"및 "안전하지 않은 문자"가 도입 된 이유는 무엇입니까? (0) | 2020.12.30 |
---|---|
유니 코드로 강제 변환 : 문자열 또는 버퍼 필요, django 관리자에서 렌더링 할 때 NoneType 발견 (0) | 2020.12.30 |
사용자가 iOS에서 이미 카메라 액세스를 거부 한 후 사용자에게 카메라 액세스를 요청하는 방법이 있습니까? (0) | 2020.12.30 |
docker-compose를 사용하여 mongo 데이터베이스를 어떻게 시드합니까? (0) | 2020.12.30 |
키보드 위에 Android SnackBar를 표시 하시겠습니까? (0) | 2020.12.30 |