Читать «Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14» онлайн - страница 9

Скотт Мейерс

Говоря о функциональном объекте, я обычно имею в виду объект типа, поддерживающего функцию-член operator(). Другими словами, это объект, действующий, как функция. Иногда я использую термин в несколько более общем смысле для обозначения чего угодно, что может быть вызвано с использованием синтаксиса вызова функции, не являющейся членом (т.е. functionName(arguments)). Это более широкое определение охватывает не только объекты, поддерживающие operator(), но и функции и указатели на функции в стиле С. (Более узкое определение происходит из С++98, более широкое — из C++11.) Дальнейшее обобщение путем добавления указателей на функции-члены дает то, что известно как вызываемый объект (callable object). Вообще говоря, можно игнорировать эти тонкие отличия и просто рассматривать функциональные и вызываемые объекты как сущности в С++, которые могут быть вызваны с помощью некоторой разновидности синтаксиса вызова функции.

Функциональные объекты, создаваемые с помощью лямбда-выражений, известны как замыкания (closures). Различать лямбда-выражения и замыкания, ими создаваемые, приходится редко, так что я зачастую говорю о них обоих как о лямбдах (lambda). Точно так же я редко различаю шаблоны функций (function templates) (т.е. шаблоны, которые генерируют функции) и шаблонные функции (template functions) (т.е. функции, сгенерированные из шаблонов функций). То же самое относится к шаблонам классов и шаблонным классам.

Многие сущности в С++ могут быть как объявлены, так и определены. Объявления вводят имена и типы, не детализируя информацию о них, такую как их местоположение в памяти или реализация:

extern int x;               // Объявление объекта

class Widget;               // Объявление класса

bool func(const Widget& w); // Объявление функции

enum class Color;           // Объявление перечисления

                            // с областью видимости

                            // (см. раздел 3.4)

Определение предоставляет информацию о расположении в памяти и деталях реализации:

int x;                    // Определение объекта

class Widget {            // Определение класса

};

bool func(const Widget& w)

 { return w.size() < 10; } // Определение функции

enum class Color

 { Yellow, Red, Blue };    // Определение перечисления

Определение можно квалифицировать и как объявление, так что, если только то, что нечто представляет собой определение, не является действительно важным, я предпочитаю использовать термин “объявление”.

Сигнатуру функции я определяю как часть ее объявления, определяющую типы параметров и возвращаемый тип. Имена функции и параметров значения не имеют. В приведенном выше примере сигнатура функции func представляет собой bool(const Widget&). Исключаются элементы объявления функции, отличные от типов ее параметров и возвращаемого типа (например, noexcept или constexpr, если таковые имеются). (Модификаторы noexcept и constexpr описаны в разделах 3.8 и 3.9.) Официальное определение термина “сигнатура” несколько отличается от моего, но в данной книге мое определение оказывается более полезным. (Официальное определение иногда опускает возвращаемый тип.)