binops["%"](10, 5); //
Здесь происходит вызов каждой из операций, хранимых в карте binops. В первом вызове возвращаемый элемент является указателем на функцию, указывающим на функцию add(). Вызов binops["+"](10, 5) использует этот указатель для вызова функции add с передачей ей значений 10 и 5. Следующий вызов, binops["-"], возвращает объект класса function, хранящий объект типа std::minus. Затем можно вызвать оператор этого объекта и других.
functionНельзя непосредственно хранить имя перегруженной функции в объекте типа function:
int add(int i, int j) { return i + j; }
Sales_data add(const Sales_data&, const Sales_data&);
map
binops.insert({"+", add}); //
Один из способов разрешения двусмысленности подразумевает хранение указателя на функцию (см. раздел 6.7) вместо имени функции:
int (*fp)(int, int) = add; //
//
binops.insert({"+", fp}); //
В качестве альтернативы для устранения неоднозначности можно использовать лямбда-выражение:
//
//
//
binops.insert({"+", [](int a, int b) {return add(a, b);} });
Вызов в теле лямбда-выражения передает два целых числа. Этому вызову может соответствовать только та версия функции add(), которая получает два целых числа, а следовательно, эта функция и применяется при выполнении лямбда-выражения.
function в новой библиотеке никак не связан с классами unary_function и binary_function, которые были частью прежних версий библиотеки. Эти классы были заменены более общей функцией bind() (см. раздел 10.3.4).
Упражнение 14.44. Напишите собственную версию простого калькулятора, способного выполнять бинарные операции.
В разделе 7.5.4 упоминалось, что неявный конструктор, который может быть вызван с одним аргументом, определяет неявное преобразование. Такие конструкторы преобразовывают объект типа аргумента в тип класса. Можно также определить преобразование из типа класса. Для этого нужно определить оператор преобразования. Конструкторы преобразования и операторы преобразования определяют
14.9.1. Операторы преобразования
operator
где — это имя типа. Операторы преобразования могут быть определены для любого типа (кроме void), который может быть типом возвращаемого значения функции (см. раздел 6.1). Преобразование в тип массива или функции недопустимо. Однако преобразование в тип указателя на данные или функцию, а также ссылочные типы вполне возможны.
У операторов преобразования нет явно заданного типа возвращаемого значения и нет параметров, их следует определять как функции-члены. Операции преобразования обычно не должны изменять преобразуемый объект. В результате операторы преобразования обычно определяют как константные члены.
Для примера определим небольшой класс, представляющий целое число в диапазоне от 0 до 255:
class SmallInt {
public:
SmallInt(int i = 0): val(i) {
if (i < 0 || i > 255)
throw std::out_of_range("Bad SmallInt value");
}
operator int() const { return val; }
private:
std::size_t val;
};
Класс SmallInt определяет преобразования в и из своего типа. Конструктор преобразует значения арифметического типа в тип SmallInt. Оператор преобразования преобразует объекты класса SmallInt в тип int:
SmallInt si;