STL 고수님들 봐주세요. ( mem_fun_ref 관련 )

freezm7의 이미지

#include <vector>
#include <set>
#include <map>
#include <iterator>
#include <functional>
#include <algorithm>

using namespace std;

// 생략 ...

set<set<int> > grps;
int x;

set<set<int> >::iterator x_iter = find_if(grps.begin(), grps.end(), 
			bind2nd(mem_fun_ref(&set<int>::count), x));

마지막 줄이 자꾸 컴파일 에러가 납니다.
혼자서 계속 머리 굴려봤는데, 해답이 안 떠오르네요.
STL 고수님, 잠시만 훑어봐 주세요.

그나저나 STL 의 매력이 장난 아니네요. :D

exsider의 이미지

set<set<int> >::iterator x_iter = find_if(grps.begin(), grps.end(), 
         bind2nd(mem_fun_ref(&set<int>::count), x)); 

아마 의도한 것은 set<int> 중에서 x 를 가지고 있는 것을 찾으려는 것으로
생각됩니다.

일단 bind2nd는 적용할 수 없습니다. bind2nd는 매개변수2개를 받는
함수의 두번째 매개변수를 고정시켜 매개변수 한개를 받는 함수로 만드는
어댑터입니다. 그런데 set<int>::count 는 매개변수를 하나만 받으므로
적용하려면 당연히 에러가 납니다.

제 생각에는 간단하게 조건함수객체를 하나 만들면 될 듯 합니다.

template<class T>
struct Temp {
    private : 
        T x;
    public:
     Temp(T v) {
         x = v;
      }
     bool operator()( const std::set<T> & s ) {
               return s.count(x);
     }
};

set<set<int> >::iterator x_iter = find_if(grps.begin(), grps.end(), 
         Temp<int>(x) ); 

테스트는 안해봤는데 아마 잘 동작할 겁니다.

doldori의 이미지

결과적으로 해결책은 되었으나 다음은 잘못 알고 계십니다.

exsider wrote:
일단 bind2nd는 적용할 수 없습니다. bind2nd는 매개변수2개를 받는
함수의 두번째 매개변수를 고정시켜 매개변수 한개를 받는 함수로 만드는
어댑터입니다. 그런데 set<int>::count 는 매개변수를 하나만 받으므로
적용하려면 당연히 에러가 납니다.

mem_fun_ref나 mem_fun에서 첫번째 인자는 그 멤버를 부르는
클래스 개체 또는 그에 대한 포인터를 뜻합니다. 즉
mem_fun(&C::f)(p, x) 는 p->f(x) 로,
mem_fun_ref(&C::f)(p, x) 는 p.f(x) 로 해석됩니다. 따라서

struct S
{
    void f(int) const { }
};

int main()
{
    vector<S> v;
    for_each(v.begin(), v.end(), bind2nd(mem_fun_ref(&S::f), 1)); // 문장 1

    for (vector<S>::iterator it = v.begin(); it != v.end(); ++it) // 문장 2
        it->f(1);
}

에서 문장 1과 2가 수행하는 내용은 동일합니다.

원래 코드가 에러나는 이유에 대해서는 저도 확실히 알지 못합니다. 저도
비슷한 일을 겪은 적이 있는데 아마 참조형과 관련된 것이 아닐까 추측만
하고 있습니다. 이번 기회에 확실히 알아봐야겠군요.

exsider의 이미지

doldori wrote:
결과적으로 해결책은 되었으나 다음은 잘못 알고 계십니다.

bind1st나 bind2nd에서 클래스의 멤버 함수의 경우 첫번째 인자는 그 멤버를
부르는 클래스 개체를 뜻합니다. 즉

mem_fun_ref(&C::f)(p, x) --> p.f(x)

로 해석됩니다. 따라서

struct S
{
    void f(int) const { }
};

int main()
{
    vector<S> v;
    for_each(v.begin(), v.end(), bind2nd(mem_fun_ref(&S::f), 1)); // 문장 1

    for (vector<S>::iterator it = v.begin(); it != v.end(); ++it) // 문장 2
        it->f(1);
}

에서 문장 1과 2가 수행하는 내용은 동일합니다.

원래 코드가 에러나는 이유에 대해서는 저도 확실히 알지 못합니다. 저도
비슷한 일을 겪은 적이 있는데 아마 참조형과 관련된 것이 아닐까 추측만
하고 있습니다. 이번 기회에 확실히 알아봐야겠군요.

알려주셔서 감사합니다. 제가 잘못알고 있었네요..

저도 확실히는 모르겠으나 아마 참조에 대한 참조의 문제로 컴파일이 안되는듯
합니다.
올리신 예제 코드에서

void f(int) const { }void f(const int &) const { } 로 바꾸면 컴파일에러가 납니다.

dev-c++ 에서는 bind2nd 가 다음 처럼 정의되어 있습니다.

template <class _Operation, class _Tp>
inline binder2nd<_Operation> 
bind2nd(const _Operation& __fn, const _Tp& __x) 

두번째 매개변수를 참조형으로 받습니다.
그런데 내부적으로 S::f(int)를 호출할 때 이 함수도 참조형을 받으므로
참조의 참조가 되어 에러가 나는 것으로 보입니다.
원래 질문하신분의 코드에서
set<T>::count 도 역시 참조를 받습니다. 아마 이게 문제인듯...

doldori의 이미지

알아본 결과 exsider 님이 지적한 대로 참조형의 참조가 문제였습니다.
자세한 내용은

http://www.boost.org/libs/functional/binders.html

의 references to references 항목을 참고하세요.
Boost에서 이에 대한 해결책을 제시하고 있습니다.
원래 코드를 고친다면

#include <boost/functional.hpp>

set<set<int> > grps; 
int x; 
set<set<int> >::iterator x_iter = find_if(grps.begin(), grps.end(),
    boost::bind2nd(boost::mem_fun_ref(&set<int>::count), x)); 

가 되겠네요.
freezm7의 이미지

이렇게까지 자세한 설명이 나오리가 기대하진 못했습니다. :D

아무튼 이 부분이 active issue list에 올라 있다니, 언젠가는 고쳐질 듯 하군요. :lol:

STL 사랑합시다~

즐겁게 살아 볼까나~*

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.