Функторы. Namespaces — различия между версиями

Материал из SEWiki
Перейти к: навигация, поиск
(Namespaces)
(Namespaces)
Строка 110: Строка 110:
 
     }
 
     }
 
   }
 
   }
   namespave Msk {
+
   namespace Msk {
 
   }
 
   }
 
}
 
}
Строка 126: Строка 126:
 
При этом поиск просматривает ВСЕ имена (переменные, функции, классы...), так как синтаксически не ясно, что именно требуется. Функции находятся независимо от количества параметров. Если искали функцию, а наткнулись на соответствующие имя класса, происходит ошибка.
 
При этом поиск просматривает ВСЕ имена (переменные, функции, классы...), так как синтаксически не ясно, что именно требуется. Функции находятся независимо от количества параметров. Если искали функцию, а наткнулись на соответствующие имя класса, происходит ошибка.
  
<source lang="cpp"
+
<source lang="cpp">
 
namespace Ru {
 
namespace Ru {
 
   // определена g(a,b)
 
   // определена g(a,b)
Строка 148: Строка 148:
 
Безымянный namespace:  
 
Безымянный namespace:  
  
 +
<source lang="cpp">
 
namespace {
 
namespace {
 
   struct test {
 
   struct test {
Строка 153: Строка 154:
 
   };
 
   };
 
}
 
}
 +
</source>
  
 
Появится уникальный namespace для каждого .cpp файла. Это позвляет создавать маленькие структуры, не боясь перекрытия имен. Компилятор авторматически добавит после него:
 
Появится уникальный namespace для каждого .cpp файла. Это позвляет создавать маленькие структуры, не боясь перекрытия имен. Компилятор авторматически добавит после него:
Строка 166: Строка 168:
 
</source>
 
</source>
  
ADL=argument dependent look up
+
ADL = argument dependent lookup.
  
namespace g
+
<source lang="cpp">
{  
+
namespace g {  
  strcut complex{};
+
  struct complex {};
  complex operator+();
+
  complex operator+();
}
+
}
g::a+%написано что-то непонятное
+
g::complex a, b;    
а=g::operator+(a,b)
+
a = a + b; //как ни странно, это сработает :)
 +
а = g::operator+(a, b);
 
    
 
    
Поиск имен ***** там где мы находимся, а также и в namespace аргументов(это первый шаг)
+
Поиск имён происходит там, где мы находимся, а также и в namespace аргументов (это первый шаг). Этот поиск называется поиском Кёнига.
 
+
Поиск Кенига.
+

Версия 12:42, 30 мая 2011

Функторы

find_if (p, q, Func); //ищет первый элемент, для которого функтор вернёт true

// Реализация функтора, который проверяет деление на 7.
struct Divby7 {
  bool operator()(int i) const {
    return i%7==0;
  }
};

// Реализация функтора, который проверяет деление на любое число, которое будет передано в конструктор.
struct Divby {
  Divby(int k) : k(k){}
  bool operator()(int i) const {
    return i%k==0;
  }
  const int k;
};

Можно писать find_if(p, q, Divby(5)), тогда в последовательности будет найден первый элемент, делящийся на 5.

stable_sort(p, qcomp_by_abs());

struct comp_by_abs {
  bool operator()(int a, int b) const {
    return abs(a) < abs(b);
  }
};

Divby - унарный предикат (одноместный функтор). comp_by_abs - бинарный предикат.

transform(p,q,out, add(7));

struct add {
  add(int k): k(k) {}
  int operator()(int a) const {
    return a+7;
  }
};

Это уже непосредственно функтор (не предикат, поскольку возвращает не 0/1).

Стандартные функторы: minus, plus, divides, modulus, multiplies, logical_and, logical_or, logical_not. Бинарные предикаты(шаблонные): less, greater, less_equal, greater_equal, not_equal_to, equal_to.

find_if(p, q, bind1st(not_equal_to<int>(), 7)); // первый элемент, не равный 7
find_if(p, q, bind2nd(greater<int>(), 7)); // первый элемент, больший 7

Кроме bind1st, bind2nd есть еще not1, not2. Для того, чтобы пользовательские функторы можно было биндить, необходимо наследовать их от стандартных классов.

struct Divby : unary_function<int, bool> {
   ...
}  
struct comp_by_abs : binary_function<int, int, bool>;

mem_fun - обёртка для member-функций (для указателей). mem_fun_ref - то же самое для ссылок. ptr_fun - обёртка для любой функции.

for_each(p, q, mem_fun_ref(vector<int>::clear));
not1(ptr_fun(is_add()));

Библиотека boost::bind:

boost::bind(vector<int>::resize,_1, 100,3);

Namespaces

 int max(int, int);
 double max(double, double);
 namespace au {
    void f(){}
 }

Чтобы вызвать f, нужно написать au::f();

 namespace noc {
  void g(){} 
 }
 namespace au {
   void g(){}
 }

namespace не является чем-то целостным. Пространства имён можно вкладывать друг в друга.

namespace Ru {
  namespace Spb {
    namespace au {
      int f();
    }
  }
  namespace Msk {
  }
}
 
Ru::spb::au::f();
::f(); //функция из глобального namespace

Если в Msk будет еще Ru, то чтобы вызвать функцию из spb из msk, надо будет писать не Ru::spb, а ::Ru::spb (коллизия двух Ru).

Поиск:

  • ищет имя в текущем namespace;
  • если не нашли, переходим выше;
  • если нашли, запускаем перегрузку.

При этом поиск просматривает ВСЕ имена (переменные, функции, классы...), так как синтаксически не ясно, что именно требуется. Функции находятся независимо от количества параметров. Если искали функцию, а наткнулись на соответствующие имя класса, происходит ошибка.

namespace Ru {
  // определена g(a,b)
  namespace spb {
    // определена g(a) 
    namesapce spbtele { 
      // вызываем g(a,b) 
    }
  }
  namespace msk {}
}

В предыдущем примере поиск остановиться в spb. Поскольку там тоже есть g. Чтобы избежать такое, надо в spb записать:

  using ::Ru::g;

НЕ НАДО=НЕЛЬЗЯ писать using namespaсe std;

Безымянный namespace:

namespace {
  struct test {
    ...
  };
}

Появится уникальный namespace для каждого .cpp файла. Это позвляет создавать маленькие структуры, не боясь перекрытия имен. Компилятор авторматически добавит после него:

using namespace <name>;

Пространствам имён можно задавать псевдонимы:

namespace a = ru::spb::au;
a::f();.

ADL = argument dependent lookup.

namespace g { 
  struct complex {};
  complex operator+();
}
g::complex a, b;   
a = a + b; //как ни странно, это сработает :)
а = g::operator+(a, b);
   
Поиск имён происходит там, где мы находимся, а также и в namespace аргументов (это первый шаг). Этот поиск называется поиском Кёнига.