2013-12-09 3 views
0

기본적으로 컨테이너 클래스를 구현하고 있습니다. 정렬 요청과 함께 전달되어야하는 비교 자 함수/functor에 따라 데이터를 정렬하는 메서드를 만들어야합니다. 메서드의 선언과 정의가 다른 파일 (.h와 .cpp)에 있기 때문에 템플릿을 사용하는 것이 문제가됩니다. 즉, 나는 방법을 만들고 싶다 :함수 또는 펑쳐를 전달할 수있는 메소드를 작성하는 방법은 무엇입니까?

void sort(function/functor f); 

나는 함수를 정의하는 방법을 모른다. 그래서,이 문제에 대한 해결책이 있습니까?

+0

는 문제가되지 않습니다 템플릿을 사용 - 단지 (보통)가 헤더에 정의 될 필요가 있음을 기억하십시오. 어떤 이유에서든 템플릿을 피하고 여분의 런타임 비용에 신경 쓰지 않는다면, 타입 지우기 대안 ('std :: function'과 같은)이 있습니다. –

+0

'sort' 함수의 본문은 얼마나 큽니까? 컨테이너에 반복자 기반 액세스를 노출 할 수있는 기회가 있습니까? – Yakk

+0

기본적으로 표준 정렬 함수에 대한 호출을 위임합니다. – user1242967

답변

4

전달할 함수/펑터의 서명을 알고있는 경우 std::function을 사용할 수 있습니다. C++ 11이 없으면 boost::function입니다. 비교기 것이 될 것이다 그래서 : Element 컨테이너의 요소의 형태가

void sort(std::function<bool(const Element&, const Element&)> f); 

.

virtual 비교 함수를 사용하여 클래스를 정의 할 수 없으며 호출자가 자신의 클래스로 해당 호출자를 파생시킬 수 있습니다. 발신자에게는 더 많은 작업이 있지만 정확히 std::function이 제공합니다. 발신자가 전화를 걸지 않아도되는 방법입니다.

두 경고 :

  • 는 헤더 파일에 있어야하지 컨테이너의 이행을위한 좋은 이유가 거기에 정말 있는지 확인하십시오. 모든 표준 컨테이너는 헤더 파일에 구현되며 대부분 제대로 작동합니다.

  • 실제로 sort 기능을 구현해야하는 좋은 이유가 있는지 확인하십시오. 표준 컨테이너는 sort 기능 만 가지고 있습니다 (std::sort이 작동하지 않음 : std::liststd::forward_list).

[*] 실제로는 std::function은 정확히 동일한 서명을 요구하지 않습니다. 호출하려는 유형과 반환 값을 변환하려는 유형을 말하면됩니다. 따라서 두 개의 숫자로 int을 호출하고 호출자가 두 개의 숫자 (long)를 사용하는 함수를 제공하면 괜찮습니다. 인수는 함수 호출과 마찬가지로 std::function없이 변환됩니다.

+0

서명을 모르는 경우에도 서명이 함수 본문에서 어떻게 호출되는지 알 수 있습니다. 'std :: function' (그리고'boost ::')은 그것이 선언 한 서명과 호환되는 *을 지울 것입니다. – Yakk

+0

@Yakk : true, 업데이트됩니다. –

+0

도움을 주셔서 감사합니다 – user1242967

2

이것은 일반적으로 템플릿으로 수행됩니다. 이처럼 :

#include <iostream> // For example output only. 

template <typename F> 
void sort(F&& pred) { 
    pred(123); 
} 

void normal_func(int v) { 
    std::cout << "normal_func(" << v << ")\n"; 
} 

struct my_pred { 
    void operator()(int v) const { 
     std::cout << "my_pred(" << v << ")\n"; 
    } 
}; 

int main() { 
    sort([](int v) { std::cout << "Called lambda func with " << v << '\n'; }); 
    sort(normal_func); 
    sort(my_pred()); 
} 

그러나 템플릿을 사용할 수없는 경우, 가장 좋은 건 std::function 같은 다형성 함수 래퍼를 사용하는 것 (또는 boost::function, 또는 당신이 당신의 자신의 간단한 버전을 쓸 수 있습니다).

또는 하드 코어 C 스타일의 일반 함수를 사용자가 상황을 저장할 수있는 void 포인터와 함께 사용할 수 있습니다. 예 : qsort(). 가능하다면 나는 거기에 가지 않으려 고 노력 하겠지만.

#include <iostream> // For example output only. 
#include <functional> // For std::function. 

void sort(const std::function<void(int)>& pred) { 
    pred(123); 
} 

void normal_func(int v) { 
    std::cout << "normal_func(" << v << ")\n"; 
} 

struct my_pred { 
    void operator()(int v) const { 
     std::cout << "my_pred(" << v << ")\n"; 
    } 
}; 

int main() { 
    sort([](int v) { std::cout << "Called lambda func with " << v << '\n'; }); 
    sort(normal_func); 
    sort(my_pred()); 
} 

는 희망이 도움이 :

여기 std::function를 사용하는 예입니다.

+0

하지만 제 경우에는 템플릿이 포함 된 솔루션이 작동합니까? 난 헤더 파일에서 일종의 선언을해야하고, .cpp 파일에는 구현이 들어있다. 내가 아는 한, 코드는 필자의 경우 컴파일되지 않을 것이다. – user1242967

+0

@ user1242967 : 그래서'std :: function'을 사용하여 예제를 제공했습니다. –

0

std::function은 Steve Jessop의 답변에서 제안한 바와 같지만,이 경우에는 블라드의 대답처럼 템플릿 함수를 템플릿 함수로 만드는 것을 고려해야한다고 생각합니다. 정렬 함수는 여러 번 비교기를 호출해야하며이 상황에서는 std::function을 사용하는 데 상당한 오버 헤드가 발생합니다. 당신은 오래된 C 표기법을 사용하여 지정하려는 경우

class C 
    { 
     template<typename T> 
     void sort(T func) 
     { 
      func(12,45); // Will compile as long as your function/functor 
     }     // Can take two integers as parameters. 
    };      // NOTE: or integers can be converted into your parameters. 

:

0

가장 쉬운 솔루션은 템플릿을 사용하는 것입니다.

typedef void (*FUNC_TYPE)(int, int); // declares a function pointer type. 
             // returns void takes two integers. 
    class C 
    { 
     void sort(FUNC_TYPE func) 
     { 
      func(12,45);      // Compiles only if the function 
     }          // matches the exact type. 
    }; 

는 C++ (11)의 방법

class C 
    { 
     void sort(std::function<void(int,int)> func) 
     { 
      func(12,45);      // Will match any func/functor that 
              // will return a void and takes two 
     }         // integers. 
    }; 
+0

물론 "C"방식은 호출 가능한 클래스 객체가 아닌 함수에서만 작동하므로이 질문에는 적용되지 않습니다. –

+0

@MikeSeymour : 나는 동의하지 않는다. 엘리먼트를 정렬 할 수있는 함수/펑터가 필요합니다 (그래서 엘리먼트 타입 만 알면됩니다). 그것은 C 스타일 함수 (비록 내가 갈 방법이 아니지만)와 잘 작동합니다. 좀 더 미묘한 것을 놓쳤나요? –

+0

@ LokiAstari : 질문자의 의도는 호출자가 함수 또는 노터 펑터를 전달할지 여부를 자유롭게 선택해야한다는 것입니다. 컨테이너 작성자가 그것을 단지 함수로 제한하는 것은 아닙니다. –