2009-03-01 2 views
2

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

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

Спасибо.

+0

Можете ли вы добавить пример использования, чтобы проиллюстрировать, как изменяется поведение? – dirkgently

ответ

3

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

например.

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

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

+0

Да. Я забыл указать на эту проблему. Пожалуйста, прочитайте раздел редактирования через минуту. –

+0

Знаете ли вы конкретные типы при использовании Предиката? Вы можете создать шаблон для структуры Finder в этих классах? Кажется, вам нужно указать конкретные типы какой-то точки. –

+0

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

1

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

+0

std :: find_if должен выбрать правильный. –

0

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

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

EDIT: Я знаю, что вы сказали, что не имеют библиотеки Повысьте эффективность доступны, но есть что-то мешает вам получать несколько файлов, которые необходимы, чтобы получить повышение :: шаблона is_convertible работает? В компиляции не было ничего особенного!

+0

Эти разные типы не относятся к отношениям. У них есть что-то общее в их логике и значении, но они не находятся в иерархии. –

0

Boost - это не волшебство; использование 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

Желаю работать. Но он даже не будет компилироваться. –

Смежные вопросы