функциональные объекты против функциональных указателей - PullRequest
10 голосов
/ 09 июня 2010

У меня есть два вопроса, связанных с функциональными объектами и указателями на функции,


Вопрос: 1

Когда я читаю различные алгоритмы использования sort STL, я вижу, что третий параметр может быть функциональным объектом, ниже приведен пример

class State {  
  public:  
    //...
    int population() const;  
    float aveTempF() const;  
    //...  
};    
struct PopLess : public std::binary_function<State,State,bool> {  
    bool operator ()( const State &a, const State &b ) const  
        { return popLess( a, b ); }  
};  
sort( union, union+50, PopLess() );  

Вопрос:

Теперь, как работает утверждение, sort(union, union+50,PopLess())? PopLess() должен быть преобразован во что-то вроде PopLess tempObject.operator(), что будет похоже на выполнение функции operator () для временного объекта. Я вижу это как передачу возвращаемого значения перегруженной операции, т.е. bool (как в моем примере) алгоритму sort.

Итак, как функция сортировки разрешает третий параметр в этом случае?


Вопрос: 2

Вопрос

Получаем ли мы какое-то конкретное преимущество от использования функциональных объектов по сравнению с указателем на функцию? Если мы воспользуемся указателем функции, приведенным ниже, он выведет какое-либо отключение?

inline bool popLess( const State &a, const State &b )
    { return a.population() < b.population(); }  
std::sort( union, union+50, popLess ); // sort by population

PS: Обе вышеупомянутые ссылки (включая пример) взяты из книги «С ++:« Общие знания: основное промежуточное программирование »» Стивена С. Дьюхерста.
Я не смог расшифровать содержание темы, поэтому написал для справки.

Заранее спасибо за помощь.

Ответы [ 6 ]

8 голосов
/ 09 июня 2010

PopLess() создает временный экземпляр класса PopLess для передачи в std::sort().Это фактически то же самое, что если бы вы сказали (обратите внимание, что в этом примере сделана дополнительная копия):

PopLess pl = PopLess();
sort(union, union + 60, pl);

Затем std::sort() вызовет operator() в этом экземпляре.

Что касается того, являются ли функциональные объекты или указатели функций лучше «лучше», это зависит.Вероятно, наиболее важным отличием является то, что функциональные объекты могут поддерживать состояние, в то время как обычные функции, передаваемые указателем, не могут.Компилятор может оптимизировать один или другой лучше, но в большинстве сценариев использования это, вероятно, не важно.

5 голосов
/ 09 июня 2010

Вопрос 1:

PopLess() должен быть преобразован во что-то вроде PopLess > tempObject.operator(), что будет аналогично выполнению функции operator () для временного объекта.

Это не [расширено, как вы сказали].PopLess() на самом деле является вызовом неявного конструктора PopLess::PopLess().Этот код создает временный объект и передает его 3-му параметру в вызове функции.

Вопрос: 2

Получаем ли мы какое-либо конкретное преимущество использования объектов функции по сравнению с указателем функции?

Не в этом случае.Здесь ваш объект PopLess не имеет состояния.Вы можете создавать функторы (функциональные объекты), которые имеют внутреннее состояние.

Пример:

struct ensure_min
{
    int value;
    ensure_min(int val) : value(val) {}
    int operator()(const int& i)
    {
        return std::max(value, i);
    }
}

std::vector<int>  values;
values.push_back(-1);
values.push_back(0);
values.push_back(1);
values.push_back(2);
values.push_back(3);

std::transform(values.begin(), values.end(), 
    std::ostream_iterator<int>(std::cout, "\n"), ensure_min(1));

Этот код выведет все числа в последовательности, гарантируя, что все числа в выходных данных имеютминимальное значение 1 (выходное значение равно 1 - если исходное число было меньше - или исходное число, если исходное число было больше или равно 1).

3 голосов
/ 09 июня 2010

Q1: PopLess() создает объект типа PopLess и sort, а затем использует этот объект для сортировки элементов в диапазоне, используя operator ().

Глядя на функцию for_each может быть проще, ее можно реализовать так:

template <typename IterT, typename Function>
Function for_each( IterT first, IterT last, Function f ) {
    for( ; first != last; ++first )
        f(*first);

    return f;
}

Таким образом, в основном for_each и sort, а функции, использующие функциональные объекты, просто берут экземпляр вашего функционального объекта и вызывают его operator ().

Q2: Компилятор может оптимизировать вызов функции путем вставки, когда вы используете объект функции, а не указатель на функцию, это может быть не так просто для компилятора, когда он делает указатель на функцию. Кроме того, функциональный объект может иметь состояние.

2 голосов
/ 09 июня 2010

Я не уверен, что задает вопрос 1, но PopLess () - это объект. Внутри функции сортировки у этого объекта есть метод operator (), вызываемый для сравнения элементов.

0 голосов
/ 12 июня 2010

Основным практическим отличием является способность функтора поддерживать состояние. Например, сортируя данные из нескольких столбцов, функтор может иметь информацию о том, по какому столбцу сортировать, направлении сортировки и даже правилах сортировки (чувствительность к регистру и т.

0 голосов
/ 09 июня 2010
  • Вопрос 1: PopLess () является временным объектом.
  • Вопрос 2: он позволяет вашей «функции» иметь состояние ... вы можете инициализировать объект любым, что вам нравится, прежде чем он получитиспользуется как функция
...