문제

find_if, count_if와 같은 STL 알고리즘에 대해 술어를 설계해야합니다.

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를 알고 있습니다. 그러나 나는 프로젝트에 부스트 ::가 없습니다. 따라서 템플릿 "has_method"를 쉽게 구현하거나 다른 디자인 솔루션을 알고 있습니다.

이 술어를 프로젝트 라이브러리 중 하나에 넣고 싶기 때문에 특정 유형을 가리키고 단순히 과부하 할 수 없습니다. "getData"메소드가있는 특정 클래스에 대해 알지 못합니다.

클래스 특성이있는 솔루션은 네임 스페이스가없는 한 좋습니다. "lib"네임 스페이스의 술어 파인더 및 "getData"가있는 클래스는 "프로그램"네임 스페이스에 있습니다.

감사.

도움이 되었습니까?

해결책

왜 템플릿 수학을 전혀 사용합니까? 클래스 유형이 많은 경우에 기반으로 원하는 특정 클래스 또는 공통 기본 클래스를 사용하십시오.

예를 들어

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_;
};

이 모든 방법의 단점은 어느 시점에서 사용할 수있는 방법으로 분할 할 수있는 유형을 알아야한다는 것입니다.

다른 팁

당신은 볼 수 있습니다 Veldhuizen의 홈페이지switch 주형. 이것을 사용하여 정확한 연산자를 선택할 수 있습니까?

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

관심이 있다면, 나는 그것을 조사하고 더 자세한 답을 줄 수 있습니다.

편집하다 :부스트 라이브러리를 사용할 수 없다고 말했지만 부스트 :: is_convertible 작동을 얻는 데 필요한 몇 가지 파일을 얻지 못하게하는 것이 있습니까? 특히 컴파일 할 것이 없을 것입니다!

부스트는 마법이 아닙니다. 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는 컴파일하지 않으면 두 번째 과부하를 제거합니다. 오버로드 해상도는 컴파일되면 두 번째 해상도를 선택합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top