Практическая разница между структурой только с operator () и нормальной функцией - PullRequest
6 голосов
/ 29 мая 2020

Я видел код, который выглядит так:

struct foo_functor {
  template <typename T, typename U>
  constexpr auto operator()(T t, U u) const -> decltype(t | u) {
    return t | u;
  }
};

constexpr foo_functor foo;

Насколько я могу судить, это то же самое, что и следующий:

template <typename T, typename U>
constexpr auto foo(T t, U u) -> decltype(t | u) {
  return t | u;
}

Зачем вам делать первый? Есть ли отличия? Насколько я мог видеть из вывода компилятора, по крайней мере, с constexpr, этого не было. А если бы они не были constexpr, в этом случае были бы какие-то различия?

Edit: Обратите внимание, что код, очень похожий на первый пример, по-видимому, использовался вместо обычных функций. 6 различных структур, все только с operator() шаблонами, все были созданы, как и в последней строке примера. Затем каждый из них использовался в точности как обычная функция.

1 Ответ

4 голосов
/ 29 мая 2020

Кто-то предположил в комментариях, что объект функции может иметь дополнительное состояние. Хотя это правда, я был бы немного более конкретным c: вы можете создать несколько копий объекта функции с различным состоянием. Если объект функции одноэлементный, то этот вопрос спорный; функция также может иметь состояние в виде глобальных переменных.

И если ваш объект функции объявлен constexpr, то ни одно из его внутренних состояний не может быть изменяемым. Это помещает ее в то же положение, что и функция constexpr: ее вызов может быть постоянным выражением, но только до тех пор, пока он не обращается к какому-либо непостоянному выражению глобальному состоянию.

Одним из важных отличий до C ++ 17 было то, что функции могли быть inline, а объекты - нет. В C ++ 14, если вы определили функтор foo в заголовке, то для каждой единицы перевода будет одна его копия. Если вам нужно, чтобы foo имел один и тот же адрес во всех единицах трансляции, вам нужно будет объявить его как функцию inline. Но в C ++ 17 объекты функций также могут быть встроенными.

Но даже если у вас есть только один экземпляр объекта функции, и он не имеет состояния, и вы используете C ++ 17 или новее , есть по крайней мере одно важное различие между этим и функцией: функции можно найти с помощью поиска, зависящего от аргументов, а объекты функций - нет. Это причина того, почему некоторые «функции» в библиотеке C ++ 20 Ranges на самом деле вообще не могут быть функциями, а должны быть объектами функций. Их неофициально называют ниблоиды .

...