У меня есть два вопроса, связанные с функциональными объектами и указателями функции,
Вопрос: 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
Мы получаем какое-либо конкретное преимущество использования функциональных объектов по сравнению с указателем функции? Если мы будем использовать ниже указателя функции, то он получит какой-либо disavantage?
inline bool popLess( const State &a, const State &b )
{ return a.population() < b.population(); }
std::sort( union, union+50, popLess ); // sort by population
PS: Оба вышеупомянутые ссылки (включая пример) являются из книги "Общепринятой истиной C++: Существенное Промежуточное Программирование" "Stephen C. Dewhurst".
Я не мог декодировать содержание темы, таким образом отправили для справки.
Заранее спасибо за Вашу справку.
PopLess ()
создает временный экземпляр класса PopLess
для передачи в std :: sort ()
. Фактически это то же самое, что если бы вы сказали (обратите внимание, что в этом примере создается дополнительная копия):
PopLess pl = PopLess();
sort(union, union + 60, pl);
Затем std :: sort ()
вызовет operator ()
на этом экземпляре.
Что касается того, что лучше "лучше" - функциональные объекты или указатели на функции, это зависит от конкретного случая. Вероятно, наиболее важным отличием является то, что объекты функций могут сохранять состояние, в то время как обычные функции, передаваемые по указателю, не могут. Компилятор может лучше оптимизировать одно или другое, но в большинстве сценариев использования это, вероятно, не важно.
Вопрос 1: PopLess()
создает объект типа PopLess
и sort
, затем использует этот объект для сортировки элементов в диапазоне с помощью оператора ()
.
Если рассматривать функцию 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: Компилятор может оптимизировать вызов функции путем инлайнинга, если вы используете объект функции, а не указатель функции, это может быть не так просто для компилятора сделать с указателем функции. Кроме того, объект функции может иметь состояние.
Я не уверен, что задает вопрос 1, но PopLess () - это объект. Внутри функции сортировки у этого объекта есть метод operator (), вызываемый для сравнения элементов.
Вопрос 1:
PopLess()
должен быть разрешен во что-то вродеPopLess > tempObject.operator()
, который будет то же самое, что и выполнение оператора () на временном объекте.
Это не [расширено, как вы сказали]. PopLess()
на самом деле является вызовом неявного конструктора PopLess::P opLess()
. Этот код создает временный объект и передает его 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).
Основное практическое отличие - это способность функтора поддерживать состояние. Например, при сортировке данных с несколькими столбцами функтор может иметь информацию о том, по какому столбцу следует сортировать, направление сортировки и даже правила сопоставления (чувствительность к регистру и т. Д.).