C++ for_each와 find1st, bind2nd에 관해 궁금한 것이 있습니다~

greathero의 이미지

typedef tr1::shared_ptr<Person> PersonPtr;
 
class A { 
public: 
  void foo();
  void test(Person p);
  void test2(Person p, int num);
private:
  std::vector<PersonPtr>* v;
 
};
 
void Person::foo() {
  int num = 100;
  for_each(v->begin(), v->end(), bind1st(mem_fun(&A::test), this)); // 무수한 삽질끝에 일단 test 함수는 호출 성공
  for_each(v->begin(), v->end(), bind(mem_fun(&A::test2), this, num)); // 컴파일 에러!!!
}

코드를 보면 아시겠지만 test와 test2라는 함수를 for_each로 실행시키려는 예제입니다.
for_each에 mem_fun(&A::test) <- 이런식으로 3번째 인자로 넣으면 만사 ok일줄 알았는데요.
이렇게 넣으면 문법상 오류는 아닌데....
"클래스에서 'operator()' 또는 사용자 정의 변환 연산자를 적절한 수의 인수를 취하는 함수 포인터 또는 함수 참조로 정의하지 않습니다."
와 같은 런타임 에러가 뜨면서 실행은 되질 않습니다.

따라서, 구글링을 해본 결과 http://stackoverflow.com/questions/4642497/passing-a-member-function-to-for-each
라는 글이 있어서 예제보고 따라했더니 첫번째 for_each는 되더라구요.
(사실, 첫번째 for_each는 그냥 &A::test를 3번째 인자로 넣어도 되지 않을까요? test 함수는 unary-function인데 말이죠ㅠ)

그런데 두번째 for_each는 도저히 실행을 못시키겠습니다...
어떻게 하면 두번째 for_each도 실행시킬 수 있을까요?
그리고 혹시 bind에 대해 제가 잘못알고 있는 개념이 있나요?

C++ 고수님들의 도움 부탁드립니다ㅠㅠ

kukyakya의 이미지

어떤 의도의 코드인지 알 수가 없어 일반적인 설명만을 남깁니다. (test 함수를 호출하는데 성공하셨다는 것도 말이 안되어 보이는 코드라..)

멤버 함수를 실행시키고자 할 때에는 어떤 멤버에 대해 멤버 함수를 실행하고자 하는지를 넘겨주셔야합니다.

A객체의 멤버 함수를 호출하려면 실제 해당 멤버 함수를 호출할 A객체의 주소를 bind의 두번째 인자로 넣어주시면 됩니다.

class A {
    ...
    void func(int a);
    ...
}

위의 A가 있을 때, a.func(3); 을 수행하는 함수자는 std::bind(&A::func, &a, 3); 과 같이 생성할 수 있습니다.

mem_fun은 C++11에서 deprecated되었으니 bind와 placeholder를 조합하시는 것을 추천합니다.

kukyakya의 이미지

원하시는 코드가 이런 코드가 아닐까 싶어 작성해보았습니다.

#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <string>
#include <memory>
 
struct Person {
  explicit Person(const std::string& name) : m_name(name) { }
 
  std::string m_name;
};
 
typedef std::shared_ptr<Person> PersonPtr;
 
struct A {
  void foo();
  void test(PersonPtr p) const { std::cout << p->m_name << std::endl; }
  void test2(PersonPtr p, int num) const { std::cout << p->m_name << ", " << num << std::endl; }
 
  std::vector<PersonPtr> v;
};
 
void A::foo() {
  int num = 100;
 
  std::for_each(v.begin(), v.end(), std::bind(&A::test, this, std::placeholders::_1));
  std::for_each(v.begin(), v.end(), std::bind(&A::test2, this, std::placeholders::_1, num));
}
 
int main()
{
  A a;
 
  a.v.push_back(PersonPtr(new Person("A")));
  a.v.push_back(PersonPtr(new Person("B")));
  a.v.push_back(PersonPtr(new Person("C")));
 
  a.foo();
}
greathero의 이미지

for_each가 도는 동안 test2 함수에 num을 100, 101, 102 이렇게 1씩 증가한 값을 넣고 싶은데
어떻게 하면 될까요? 인수로 고정된 값만 넘겨줄 수 밖에 없나요?

philnet의 이미지

그 목적이라면, test 함수가 int& 를 받아서 수정하게 하면 되지 않을까요? 다음과 같이요...

...
struct A {
    ...
    void foo2();
    ...
    void test3(PersonPtr p, int& num) const { test2(p, num++); }
    ...
}
 
void A::foo2() {
    int num = 100;
    std::for_each(v.begin(), v.end(), std::bind(&A::test3, this, std::placeholders::_1, num));
}
...

만약 test 함수에 넘기는 데이터가 1씩 증가시키는 것보다 더 다양하고 복잡한 규칙이 필요하다면, 해당 규칙에 맞는 데이터를 생성하는 함수객체를 만들어서 사용할 필요가 있을 듯요.

kukyakya의 이미지

그 때는 그냥 for문을 이용하시는 편이 더 낫습니다.

int num = 100;
for(std::vector<PersonPtr>::const_iterator it = v.begin(), e = v.end(); it != e; ++it) {
	a.test2(*it, num++);
}

C++11을 지원하는 컴파일러를 사용중이시면 표현이 좀 더 편한데,

for문을 사용하는 방법:

int num = 100;
for(const PersonPtr& p : v) { a.test2(p, num++); }

for_each + lambda를 사용하는 방법:

int num = 100;
std::for_each(v.begin(), v.end(), [&](const PersonPtr& p) { a.test2(p, num++); });

정도가 가능합니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.