Question

Je dois désigner un prédicat pour des algorithmes stl tels que 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_ );
        }*/ 
    };
}

Mais j’en ai besoin pour avoir différents opérateurs () en fonction de la présence de certaines méthodes dans TElement. Comme si elle avait " getData " J'aimerais vérifier ces données et si ce n'était pas le cas, je ferais d'autres actions.

Je connais SFINAE. Mais je n'ai pas de boost :: sur le projet. Donc, soit il existe une implémentation facile du modèle " has_method " ou si vous connaissez une autre solution de conception.

Je ne peux pas pointer des types spécifiques ni simplement les surcharger, car je voudrais placer ce prédicat dans celle de la bibliothèque de projet, qui ne connaît pas ces classes spécifiques avec l'option "getData". méthode.

Les solutions avec des traits de classe sont utiles dans la mesure où il n’ya pas d’espace de nommage. Recherche de prédicat dans in " lib " espace de noms et classe avec " getData " est en " programme " espace de noms.

Merci.

Était-ce utile?

La solution

Pourquoi utiliser des méthodes de template? Utilisez simplement la classe spécifique sur laquelle vous souhaitez vous baser ou une classe de base commune s'il existe de nombreux types de classe.

par exemple

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

Si ce modèle se produit souvent avec différents types de classes et que vous connaissez ces types avant d'utiliser le prédicat, vous pouvez créer un modèle pour le prédicat lui-même.

par exemple

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

Une autre approche que vous pouvez utiliser consiste à utiliser une sorte de trait de classe pour conserver les informations.

par exemple

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

L’inconvénient de toutes ces méthodes est qu’à un moment donné, vous devez connaître les types pour pouvoir les diviser en différentes méthodes.

Autres conseils

Vous pouvez consulter la page d'accueil de Veldhuizen pour le modèle switch . Vous pouvez probablement l'utiliser pour choisir l'opérateur exact?

Faites en sorte que vos types proviennent de " types de fonctionnalités " (par exemple, un type "has_function1") qui fonctionnera comme une interface java et vous aurez une chance, car SFINAE peut être utilisé pour tester si un type peut être converti en un autre.

Si cela vous intéresse, je peux l'examiner et vous donner une réponse plus détaillée.

MODIFIER: Je sais que vous avez dit que vous n'aviez pas de bibliothèques Boost disponibles, mais y a-t-il quelque chose qui vous empêche d'obtenir les quelques fichiers nécessaires pour que boost :: is_convertible fonctionne? Il n'y aurait rien de particulier à compiler!

Le boost n’est pas magique; utiliser SFINAE est assez simple:

    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 supprimera la seconde surcharge s'il ne compile pas. La résolution de surcharge choisira la seconde, si elle compile car ... est pire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top