C11 7.21.6.2p3 говорит следующее из fscanf
и др.:
3 [...] Каждая спецификация преобразования вводится символом
%
, После%
в последовательности появляется следующее:blockquote>
- Необязательный символ подавления присвоения
*
.- Необязательное десятичное целое число, большее нуля, которое задает максимальную ширину поля (в символах).
- Необязательный модификатор длины, который определяет размер принимающего объекта.
- Символ спецификатора преобразования, который указывает тип преобразования, которое будет применено.
Модификатор длины означает дополнительную букву (буквы), например
l
в%lf
, что означаетdouble
. Обратите внимание, что хотя%2f
будет действительным и будет означать, что можно использовать только до 2 символов ввода, нигде не сказано, что вы можете написать%.2f
, т. Е.%.2f
является неверной спецификацией преобразования, и, следовательно, поведение undefined ( C11 7.2.6.2p13 ).
Наследование от [unary|binary] _function просто дает Вам дополнительные определения типов в Вашем классе:
Для unary_function
argument_type
result_type
Для binary_function
first_argument_type
second_argument_type
result_type
, Которые являются теми типами, которые Вы передаете [unary|binary] _function. В Вашем случае нет никаких преимуществ.
, Если когда-нибудь собирающийся использовать Ваши Функторы с другими Функторами станд. modificators как not1, bind1st Вы необходимо наследоваться [unart|binart] _function.
И если Вы собираетесь хранить эту шаблонную информацию для своей цели, лучше использовать готовое решение.
Помимо определений типов (уже упомянутый), существует также как аспект удобочитаемости. То, когда я буду видеть struct Foo {...
, моей первой мыслью будет "Foo, является типом". Но с struct Foo : public unary_function<...
я уже знаю, что Foo является функтором. Для программиста (в отличие от компиляторов), типы и функторы довольно отличны.
Как Mykola объясняет, они просто добавляют определения типов. Вообразите для Вашего PersonGreater
, Вы хотите зафиксировать первый аргумент некоторому человеку. Эти binder1st
должен был бы сохранить первый аргумент где-нибудь, и таким образом, ему нужен тип первого аргумента. binary_function
обеспечивает что как определение типа:
// get a function object that compares person1 against
// another person
std::bind1st(PersonGreater(), person1)
Теперь, возвращенный binder1st
объект знает, что тип аргумента, который он должен сохранить, имеет Человека типа.
Некоторые функциональные объекты инвертируют результат другого функционального объекта. Здесь нам нужен тип аргумента также:
template <class Predicate>
class unary_negate
: public unary_function<typename Predicate::argument_type,bool> {
Predicate pred;
public:
explicit unary_negate(const Predicate& pred):pred(pred) { }
bool operator()(const typename Predicate::argument_type& x) const {
return !pred(x);
}
};
, Который мог также использовать шаблонное operator()
, но Стандарт определяет его для использования эти argument_type
тип как параметр. Сам инвертор получен из unary_function и должен обеспечить первый тип аргумента так или иначе.
Иногда, люди пытаются использовать [unary,binary]_function
для хранения функциональных объектов/указателей. Однако они не могут использоваться для этого. boost::function
выполняет то задание и будет принят в следующем Стандарте как [1 110].
Это - сильная форма документации, осуществленной компилятором.
Путем наследования, Вы делаете обещание, что Вы реализуете интерфейс binary_function, и компилятор будет содержать Вас к нему. Затем клиенты могут положить, что Ваш класс может использоваться везде, где binary_function необходим.