2009-03-01 5 views
2

find_if, count_if와 같은 stl 알고리즘을위한 술어를 설계해야합니다.stl 알고리즘을위한 C++ "스마트"술어

namespace lib 
{ 
    struct Finder 
    { 
     Finder(const std::string& name): 
      name_(name) 
     { 
     } 

     template< typename TElement > 
     bool operator(const TElement& element) 
     { 
      return element.isPresent(name_); 
     } 

     /* template< typename TElement > 
     bool operator(const TElement& element) 
     { 
      const Data& data = element.getData(); 
      return data.isPresent(name_); 
     }*/ 
    }; 
} 

하지만 TElement의 일부 특정 메서드가 있는지에 따라 다른 연산자()가 있어야합니다. 마치 "getData"가있는 것처럼 데이터를 확인하고 싶지 않은 경우 다른 작업을 수행합니다.

나는 SFINAE를 알고 있습니다. 그러나 나는 프로젝트에 boost ::가 없다. 그래서 "has_method"템플릿을 쉽게 구현하거나 다른 디자인 솔루션을 알고 있습니다.

이 형식을 "getData"메서드가있는 특정 클래스에 대해 알지 못하는 프로젝트 라이브러리 중 하나에 넣으 려하므로 특정 형식을 지정하고 단순히 오버로드 할 수 없습니다.

클래스 특성이있는 솔루션은 네임 스페이스가없는 한 좋습니다. "lib"네임 스페이스의 Predicate Finder와 "getData"가있는 클래스는 "program"네임 스페이스에 있습니다.

감사합니다.

+0

동작을 변경하는 방법을 보여주기 위해 예제 사용을 추가 할 수 있습니까? – dirkgently

답변

3

왜 템플릿 mathod를 사용합니까? 기본 클래스로 사용하려는 특정 클래스를 사용하거나 클래스 유형이 많은 경우 공통 기본 클래스를 사용하십시오.

struct Finder 
{ 
    Finder(const std::string& name): 
     name_(name) 
    { 
    } 

    bool operator(const IsPresentBaseClass& element) 
    { 
     return element.isPresent(name_); 
    } 

    bool operator(const GetDataBaseClass& element) 
    { 
     const Data& data = element.getData(); 
     return data.isPresent(name_); 
    } 
}; 

이 패턴이 다른 클래스 유형에서 많이 발생하고 술어를 사용하기 전에 유형을 알고 있으면 술어 자체를 템플릿으로 만들 수 있습니다.

template<class T1, class T2> 
struct Finder 
{ 
    Finder(const std::string& name): 
     name_(name) 
    { 
    } 

    bool operator(const T1& element) 
    { 
     return element.isPresent(name_); 
    } 

    bool operator(const T2& element) 
    { 
     const Data& data = element.getData(); 
     return data.isPresent(name_); 
    } 
}; 

또는 다른 종류의 클래스 특성을 사용하여 정보를 보유 할 수도 있습니다.

struct UseIsPresent 
{ 
    template<class T> 
    static bool CompareElement(const T& element, const std::string& name) 
    { 
     return element.isPresent(name); 
    } 
}; 

struct UseGetData 
{ 
    template<class T> 
    static bool CompareElement(const T& element, const std::string& name) 
    { 
     const Data& data = element.getData(); 
     return data.isPresent(name); 
    } 
}; 

// default to using the isPresent method 
template <class T> 
struct FinderTraits 
{ 
    typedef UseIsPresent FinderMethodType; 
}; 

// either list the classes that use GetData method 
// or use a common base class type, e.g. UseGetData 
template <> 
struct FinderTraits<UseGetData> 
{ 
    typedef UseGetData FinderMethodType; 
}; 

struct Finder 
{ 
    Finder(const std::string& name) 
    : name_(name) 
    { 
    } 

    template<class T> 
    bool operator()(const T& element) 
    { 
     return FinderTraits<T>::FinderMethodType::CompareElement<T>(element, name_); 
    } 

    std::string name_; 
}; 

모든 방법의 단점은 어떤 시점에서 당신이 사용하는 어떤 방법으로 그들을 분할 할 수 있도록 유형을 알 필요가 있다는 것입니다.

+0

예. 나는이 문제를 지적하는 것을 잊었다. 잠시 후에 편집 섹션을 읽으십시오. –

+0

술어 사용시 특정 유형을 알고 있습니까? 해당 클래스에서 Finder 구조체를 템플릿으로 만들 수 있습니까? 그냥 구체적인 유형을 지정해야 할 필요가있는 것 같습니다. –

+0

유형을 모르는 경우 클래스 특성과 같은 것을 사용하여 유형을 파악할 수 있습니다. 최소한 모든 공통 기본 클래스 유형 또는 관련된 모든 클래스의 특성을 설정해야합니다. –

1

switch 템플릿의 경우 Veldhuizen's homepage을 볼 수 있습니다. 아마 정확한 연산자를 선택하기 위해 이것을 사용할 수 있을까요?

+0

std :: find_if 올바른 것을 선택해야합니다. –

0

SFINAE를 사용하여 한 유형을 다른 유형으로 변환 할 수 있는지 테스트 할 수 있기 때문에 유형이 "기능 유형"(예 : "has_function1"유형)에서 파생 된 경우 Java 인터페이스로 작동하고 기회가 있습니다.

관심이 있으시면 그 부분을 살펴보고 좀 더 자세한 답변을 드릴 수 있습니다.

편집 : 나는 당신이 사용할 수 부스트 라이브러리를하지 않았다 알고 있지만 아무것도 향상 얻을하는 데 필요한 몇 가지 파일을 얻기에서 당신을 방지 :: is_convertible 작업이 무엇입니까? 특히 컴파일하는 데 아무 것도 없습니다!

+0

다른 유형은 관계에 없습니다. 그들은 논리와 의미에서 공통점이 있지만 계층 구조에 없습니다. –

0

부스트는 마법이 아닙니다. SFINAE를 사용하면 상당히 간단합니다.

template< typename TElement > 
    bool operator(const TElement& element, ...) 
    { 
     return element.isPresent(name_); 
    } 

    template< typename TElement > 
    bool operator(const TElement& element, const Data& data = element.getData()) 
    { 
     return data.isPresent(name_); 
    } 

SFINAE는 컴파일되지 않으면 두 번째 오버로드를 제거합니다. 과부하 해결은 ... 두 번째를 선택합니다. 왜냐하면 컴파일은 ... 더 나쁜 일치이기 때문입니다.

+0

나는 그것이 좋으면 좋겠다. 그러나 컴파일되지 않습니다. –