본문 바로가기
컴퓨터/디버깅

less 를 찾을 수 없어서 에러가 난 경우

by adnoctum 2012. 5. 20.



   에러 메세지는 다음과 같다. 


c:\program files (x86)\microsoft visual studio 10.0\vc\include\xfunctional(125): error C2784: 'bool std::operator <(const std::move_iterator<_RanIt> &,const std::move_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::move_iterator<_RanIt> &' from 'const CHARRANGE'


작업 환경 : Visual C++ 10.0 (VS2010) on Windows 7 Professional, SP1, (English)



F4 를 누르거나 위의 에러 메세지 출력 줄을 더블 클릭하면 다음과 같은 파일이 열린다. 


  118         // TEMPLATE STRUCT less

  119 template<class _Ty>

  120     struct less

  121         : public binary_function<_Ty, _Ty, bool>

  122     {    // functor for operator<

  123     bool operator()(const _Ty& _Left, const _Ty& _Right) const

  124         {    // apply operator< to operands

  125         return (_Left < _Right);

  126         }

  127     };


에러가 난 줄은 125 번 째 인데, xfunctional 파일인데, 제공되는 파일이므로 당연히 여기서 문제가 될 일은 거의 없고, 따라서 문제는 내가 작성한 코드에 있어야 한다. 


   이제 추정을 해보자. 위의 125번째 줄은 operator< 를 [_Left] 와 [_Right] 의 operand 에 적용할 수 없었기 때문에 일어난 것이다. 위 에러 메세지를 보면 대략 CHARRANGE 라는 구조체에 이 연산자를 적용하려 했음을 알 수 있다. 내가 작성한 코드에는 그러나 operator< 를 호출하거나 less 를 함수 객체로 사용하는 곳이 없다. 대신, 


   36 template<class T>

   37 bool uniq(std::vector<T>* v)

   38 {

   39     ASSERT( v != NULL);

   40     if(v->empty() == true) return false;

   41 

   42     std::set<T> s(v->begin(), v->end());

   43     v->clear();

   44     v->insert(v->begin(), s.begin(), s.end());

   45 

   46     return true;

   47 }


위와 같은 함수가 있고, 


  183     std::vector<CHARRANGE> herb_boundary;

  184     find_boundary(herb_position, &herb_boundary);

  185     uniq(&herb_boundary);


위처럼 uniq 함수를 호출하는 부분이 있다. 즉, 나는 CHARRANGE 구조체를 요소로 같는 herb_boundary 라는 변수를 만든 후, 이 변수를 uniq[각주:1] 함수에 전달하고, uniq 함수에서 이 요소들을 set 에 집어 넣으려 하고 있다. 문제는 set 의 경우 효율성을 위해 set 안에 들어가는 요소를 정렬을 해서 저장하게 되는데 이 때 binary search 를 이용한다. 따라서 요소의 대소비교가 가능해야 하기에 operator< 를 set 에 집어 넣는 요소에 적용하게 된다. 바로 이 부분이다. 이 부분에서 CHARRANGE 구조체에 적용할 operator< 가 없었기 때문에 set 에 집어 넣을 수 없었고, 그래서 컴파일 에러가 난 것이다. 



   어떻게 해결해야 할까? 보통 set 이나 map 처럼 operator< 를 사용하여 container 에 객체를 집어 넣을 경우, operator< 를 적용할 수 없는 요소를 집어 넣을 경우 두 가지 방법을 사용할 수 있다. 별도의 함수 객체를 만들어서 set 이나 map 의 정의시 함수 객체를 같이 써 주거나, 집어 넣을 요소의 클래스 자체에 operator< 를 정의해 주는 것이다. 나의 경우는 다음과 같이 전자를 따랐다. 


   49 class range_order{

   50 public:

   51     bool operator()(const CHARRANGE& op1, const CHARRANGE& op2) const

   52     {

   53         if(op1.cpMax == op2.cpMax){

   54             return op1.cpMin < op2.cpMin;

   55         }

   56         else{

   57             return op1.cpMax < op2.cpMax;

   58         }

   59         return false;

   60     }

   61 };

   62 

   63 template<class T, class L>

   64 bool uniq(std::vector<T>* v)

   65 {

   66     ASSERT( v != NULL);

   67     if(v->empty() == true) return false;

   68 

   69     std::set<T,L> s(v->begin(), v->end());

   70     v->clear();

   71     v->insert(v->begin(), s.begin(), s.end());

   72 

   73     return true;

   74 }



위처럼 함수 객체를 정의해 주고, 


  185     uniq<CHARRANGE,range_order>(&herb_boundary);


위처럼 호출해 준다. 즉, CHARRANGE 구조체를 받아서 순서를 정해 주는 함수 객체 range_order 를 정의해 준 후, uniq 함수에 이 함수 객체도 같이 제공해 주는 것이다. 이를 위해서, 요소의 타입과 그 타입의 순서를 정해 주는 함수 객체 두 개를 받는 uniq 함수를 추가해 준다. 


아, ..., STL의 이 확장성이란.








  1. 코드 중 185 번 줄은 uniq<CHARRANGE>(&herb_boundary); 이어야 하는데, VC++ 의 경우 알아서 해주기도 한다. 내가 디버깅 하다 이 부분을 살짝 빼 먹은 것을 알았는데, VC++ 이 다 알아서 해주긴 해도 그래도 위처럼 명시적으로 써 주는 게 좋다. ㅋ. [본문으로]