C ++ «умный» предикат для алгоритма stl - PullRequest
2 голосов
/ 01 марта 2009

Мне нужно создать предикат для алгоритмов stl, таких как 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_ );
        }*/ 
    };
}

Но мне нужны разные операторы () в зависимости от наличия некоторых методов в TElement. Например, если у него есть «getData», я бы хотел проверить эти данные, а если у него его нет, я бы сделал несколько других действий.

Я знаю о СФИНАЕ. Но у меня нет поддержки :: в проекте. Так что либо есть простая реализация шаблона has_method, либо вы знаете другое дизайнерское решение.

Я не могу указать конкретные типы и просто перегрузить, потому что я хотел бы поместить этот предикат в библиотеку проекта, которая не знает об этих конкретных классах с помощью метода "getData".

Решение с чертами классов хорошо, поскольку нет пространств имен. Средство поиска предикатов в пространстве имен «lib», а класс с «getData» - в пространстве имен «program».

Спасибо.

Ответы [ 4 ]

3 голосов
/ 01 марта 2009

Зачем вообще использовать шаблоны? Просто используйте определенный класс, на котором вы хотите его основывать, или общие базовые классы, если существует много типов классов.

, например

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

Недостатки всех этих методов в том, что в какой-то момент вам нужно знать типы, чтобы можно было разбить их на используемые методы.

1 голос
/ 01 марта 2009

Вы можете посмотреть домашнюю страницу Veldhuizen для шаблона switch. Вы, вероятно, можете использовать это, чтобы выбрать точного оператора?

0 голосов
/ 02 марта 2009

Повышение не волшебство; Использование 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 голосов
/ 01 марта 2009

Ваши типы имеют производные от "типов функциональности" (например, типа "has_function1"), которые будут работать как интерфейсы Java, и у вас есть шанс, потому что SFINAE может использоваться для проверки того, можно ли один тип преобразовать в другой.

Если вам интересно, я могу изучить его и дать вам более подробный ответ.

РЕДАКТИРОВАТЬ: Я знаю, что вы сказали, что у вас нет доступных библиотек Boost, но есть что-то, что мешает вам получить несколько файлов, необходимых для работы boost :: is_convertible? Там не было бы ничего конкретного для компиляции!

...