В чем преимущество наследования от функции std :: binary_function (или функции std :: unary)? - PullRequest
27 голосов
/ 04 марта 2009

В чем преимущество наследования от std :: binary_function (или std :: unary_function)?

Например, у меня есть такой код:

class Person
{
 public:
    Person();
    Person(int a, std::string n);
    Person(const Person& src);

    int age;
    std::string name;
 };

 Person::Person()
           : age(0)
             , name("")
               {};

 Person::Person(int a, std::string n)
 : age(a)
 , name(n)
 {};

 Person::Person(const Person& src)
 {
   age = src.age;
   name = src.name;
 };

 struct PersonPrint : public std::unary_function<Person, void>{
   void operator() (Person p){
     std::cout << " Person age: " << p.age 
               << " name: " << p.name << std::endl;
   }
 };

 struct PersonGreater : public std::binary_function<Person, Person, bool>{
   bool operator()(const Person& p1, const Person p2){
     if (p1.age > p2.age) return true;
     if (p1.name.compare(p2.name) > 0) return true;
     return false;
   }
 };

 int main(int count, char** args)
 {
   std::vector<Person> personVec;
   Person p1(10, "Person1");
   Person p2(12, "Person2");
   Person p3(12, "Person3");

   personVec.push_back(p1);
   personVec.push_back(p2);
   personVec.push_back(p3);

   std::cout << "before sort: " << std::endl;
   std::for_each(personVec.begin(), personVec.end(), PersonPrint());
   std::sort(personVec.begin(), personVec.end(), PersonGreater());
   std::cout << "after: " << std::endl;
   std::for_each(personVec.begin(), personVec.end(), PersonPrint());
 }

Но я также мог написать этот код без формы наследования std::unary_function/std::binary_function?

 struct PersonPrint {
     void operator() (Person p) {
         std::cout << " Person age: " << p.age << " name: " << p.name << std::endl; 
     } 
 }; 

 struct PersonGreater {
     bool operator()(const Person& p1, const Person p2) {
         if (p1.age > p2.age) return true; 
         if (p1.name.compare(p2.name) > 0) return true; 
         return false; 
     } 
 };

ОБНОВЛЕНО

std :: binary_function и std :: unary_function устарели с C ++ 11, см. Комментарий @ AlexandreC.

Ответы [ 4 ]

29 голосов
/ 04 марта 2009

Наследование от функции [unary | binary] _ просто дает вам дополнительные определения типов в вашем классе:

Для унарной функции

argument_type
result_type

Для двоичной_функции

first_argument_type
second_argument_type
result_type 

Какие типы вы передаете функции [унарная | двоичная] _. В вашем случае нет никаких преимуществ.

Если вы когда-либо собираетесь использовать свои Функторы с другими модификаторами стандартных функций, такими как not1, bind1st вы должны наследовать от функции [unart | binart] _.

И если вы собираетесь хранить информацию этого шаблона для своих целей, лучше использовать готовое решение.

16 голосов
/ 04 марта 2009

Помимо typedefs (уже упоминалось), есть также аспект удобочитаемости. Когда я вижу struct Foo {..., моей первой мыслью будет «Foo - это тип». Но с struct Foo : public unary_function<... я уже знаю, что Фу - функтор. Для программиста (в отличие от компиляторов) типы и функторы совершенно различны.

9 голосов
/ 04 марта 2009

Как объясняет Николай, они просто добавляют typedefs. Представьте, что для вашего PersonGreater вы хотите исправить первый аргумент для какого-то человека. binder1st должен был бы где-то хранить первый аргумент, и поэтому ему нужен тип первого аргумента. binary_function обеспечивает это как typedef:

// get a function object that compares person1 against 
// another person
std::bind1st(PersonGreater(), person1)

Теперь возвращенный объект binder1st знает, что тип аргумента, который нужно сохранить, имеет тип Person.

Некоторые функциональные объекты сводят на нет результат другого функционального объекта. Здесь нам также нужен тип аргумента:

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 выполняет эту работу и будет принят в следующем стандарте как std::function.

3 голосов
/ 04 марта 2009

Это строгая форма документации, применяемая компилятором.

Унаследовав, вы даете обещание, что реализуете интерфейс binary_function, и компилятор вас поддержит Тогда клиенты могут поверить, что ваш класс может использоваться везде, где требуется двоичная функция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...