Pergunta

Eu preciso predicado designe para algoritmos STL como find_if, count_if.

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_ );
        }*/ 
    };
}

Mas eu preciso dele para ter operadores diferentes () de acordo com a presença de alguns determinados métodos em TElement. Como se ele tem "getData" Eu gostaria de verificar que os dados e se não tiver eu faria algumas outras ações.

Estou ciente SFINAE. Mas eu não tenho boost :: no projeto. Então, ou existe algum fácil implementação do modelo "has_method" ou você sabe alguma outra solução de design.

Não consigo tipos ponto específico e simplesmente sobrecarregar porque eu gostaria de colocar esse predicado para o da biblioteca do projeto, que não sei sobre essas classes específicas com método "getData".

Solução com traços de classe são boas, tanto quanto não há namespaces. Predicado do Finder no no namespace "lib" e classe com "getData" está no namespace "programa".

Graças.

Foi útil?

Solução

mathods Por modelo serve para nada? Basta usar a classe específica que pretende baseá-lo em aulas ou uma base comum, se há muitos tipos de classes.

por exemplo.

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

Se esse padrão acontece muito com diferentes tipos de classes e você sabe os tipos antes de usar o predicado você poderia modelo o próprio predicado.

por exemplo.

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

Ou uma outra abordagem que você pode usar é usar algum tipo de traços de classe para armazenar as informações.

por exemplo.

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

As desvantagens de todos estes métodos é que em algum momento você precisa saber os tipos de ser capaz de dividi-los em qual método usar.

Outras dicas

Você pode ter um olhar para homepage de Veldhuizen para o modelo switch. Provavelmente, você pode usar isso para escolher o operador exata?

Tenha os seus tipos derivam de "tipos de funcionalidade" (por exemplo, um tipo de "has_function1") que funcionará como interfaces Java e você tem uma chance, porque SFINAE pode ser usado para testar se um tipo pode ser convertido em um outro.

Se você estiver interessado, eu posso olhar para ele e dar-lhe uma resposta mais detalhada.

EDIT: Eu sei que você disse que não tem bibliotecas de impulso disponíveis, mas há alguma coisa impedindo-o de obter os poucos arquivos que são necessários para obter boost :: trabalho is_convertible? Não haveria nada em particular para compilar!

impulso não é mágica; usando SFINAE é bastante simples:

    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 irá remover o segundo sobrecarga se não compilar. resolução de sobrecarga irá escolher o segundo, se isso acontecer de compilação desde ... é um jogo pior.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top