Вопрос

Мне нужно разработать предикат для алгоритмов 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», я бы хотел проверить эти данные, а если нет, я бы выполнил некоторые другие действия.

Я знаю о SFINAE.Но у меня нет ускорения::на проекте.Итак, либо есть какая-то простая реализация шаблона «has_method», либо вы знаете какое-то другое дизайнерское решение.

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

Решение с признаками класса хорошо, поскольку нет пространств имен.Predicate Finder находится в пространстве имен «lib», а класс с «getData» находится в пространстве имен «program».

Спасибо.

Это было полезно?

Решение

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

например

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

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

Другие советы

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

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

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

РЕДАКТИРОВАТЬ :Я знаю, вы сказали, что у вас нет доступных библиотек Boost, но есть ли что-нибудь, что мешает вам получить несколько файлов, необходимых для работы boost::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