Функторы. Namespaces — различия между версиями
Ivan (обсуждение | вклад) |
(→Namespaces) |
||
(не показано 7 промежуточных версий 2 участников) | |||
Строка 1: | Строка 1: | ||
− | == Функторы | + | == Функторы == |
+ | <source lang="cpp"> | ||
+ | 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){} | Divby(int k) : k(k){} | ||
− | bool operator()(int i) const | + | bool operator()(int i) const { |
− | + | ||
return i%k==0; | return i%k==0; | ||
} | } | ||
const int k; | const int k; | ||
− | + | }; | |
+ | </source> | ||
− | Можно писать | + | Можно писать find_if(p, q, Divby(5)), тогда в последовательности будет найден первый элемент, делящийся на 5. |
+ | <source lang="cpp"> | ||
+ | stable_sort(p, qcomp_by_abs()); | ||
− | + | struct comp_by_abs { | |
− | + | bool operator()(int a, int b) const { | |
− | + | return abs(a) < abs(b); | |
− | + | ||
− | bool operator()(int a, int b)const | + | |
− | + | ||
− | return abs(a)<abs(b); | + | |
} | } | ||
− | + | }; | |
− | + | </source> | |
− | Divby - унарный предикат. | + | Divby - унарный предикат (одноместный функтор). |
comp_by_abs - бинарный предикат. | comp_by_abs - бинарный предикат. | ||
+ | <source lang="cpp"> | ||
transform(p,q,out, add(7)); | transform(p,q,out, add(7)); | ||
− | + | struct add { | |
− | + | add(int k): k(k) {} | |
− | add(int k): k(k){} | + | int operator()(int a) const { |
− | int operator()(int a)const | + | |
− | + | ||
return a+7; | return a+7; | ||
} | } | ||
− | + | }; | |
+ | </source> | ||
− | + | Это уже непосредственно функтор (не предикат, поскольку возвращает не 0/1). | |
− | + | ||
− | + | Стандартные функторы: minus, plus, divides, modulus, multiplies, logical_and, logical_or, logical_not. | |
+ | Бинарные предикаты(шаблонные): less, greater, less_equal, greater_equal, not_equal_to, equal_to. | ||
− | + | <source lang="cpp"> | |
− | + | find_if(p, q, bind1st(not_equal_to<int>(), 7)); // первый элемент, не равный 7 | |
− | find_if(p,q,bind2nd(greater<int>(),7)) | + | find_if(p, q, bind2nd(greater<int>(), 7)); // первый элемент, больший 7 |
+ | </source> | ||
Кроме bind1st, bind2nd есть еще not1, not2. | Кроме bind1st, bind2nd есть еще not1, not2. | ||
+ | Для того, чтобы пользовательские функторы можно было биндить, необходимо наследовать их от стандартных классов. | ||
+ | <source lang="cpp"> | ||
+ | struct Divby : unary_function<int, bool> { | ||
+ | ... | ||
+ | } | ||
+ | struct comp_by_abs : binary_function<int, int, bool>; | ||
+ | </source> | ||
− | + | mem_fun - обёртка для member-функций (для указателей). | |
− | + | mem_fun_ref - то же самое для ссылок. | |
− | + | ptr_fun - обёртка для любой функции. | |
− | + | <source lang="cpp"> | |
− | + | for_each(p, q, mem_fun_ref(vector<int>::clear)); | |
+ | not1(ptr_fun(is_add())); | ||
+ | </source> | ||
− | + | Библиотека boost::bind: | |
− | + | <source lang="cpp"> | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | Библиотека boost::bind | + | |
boost::bind(vector<int>::resize,_1, 100,3); | boost::bind(vector<int>::resize,_1, 100,3); | ||
− | + | </source> | |
− | + | ||
== Namespaces == | == Namespaces == | ||
− | int max(int, int) | + | <source lang="cpp"> |
− | double max(double, double) | + | int max(int, int); |
− | namespace au | + | double max(double, double); |
− | + | namespace au { | |
void f(){} | void f(){} | ||
} | } | ||
+ | </source> | ||
Чтобы вызвать f, нужно написать au::f(); | Чтобы вызвать f, нужно написать au::f(); | ||
− | namespace noc | + | <source lang="cpp"> |
− | + | namespace noc { | |
void g(){} | void g(){} | ||
} | } | ||
− | namespace au | + | namespace au { |
− | + | ||
void g(){} | void g(){} | ||
} | } | ||
+ | </source> | ||
+ | |||
+ | namespace не является чем-то целостным. Пространства имён можно вкладывать друг в друга. | ||
− | + | <source lang="cpp"> | |
− | + | namespace Ru { | |
− | + | namespace Spb { | |
− | namespace Spb{ | + | namespace au { |
− | + | int f(); | |
− | + | } | |
− | + | ||
} | } | ||
− | + | namespace Msk { | |
− | + | } | |
+ | } | ||
Ru::spb::au::f(); | Ru::spb::au::f(); | ||
+ | ::f(); //функция из глобального namespace | ||
+ | </source> | ||
− | + | Если в Msk будет еще Ru, то чтобы вызвать функцию из spb из msk, надо будет писать не Ru::spb, а ::Ru::spb (коллизия двух Ru). | |
− | + | Поиск: | |
+ | * ищет имя в текущем namespace; | ||
+ | * если не нашли, переходим выше; | ||
+ | * если нашли, запускаем перегрузку. | ||
+ | При этом поиск просматривает ВСЕ имена (переменные, функции, классы...), так как синтаксически не ясно, что именно требуется. Функции находятся независимо от количества параметров. Если искали функцию, а наткнулись на соответствующие имя класса, происходит ошибка. | ||
− | + | <source lang="cpp"> | |
− | + | namespace Ru { | |
− | + | // определена g(a,b) | |
− | + | namespace spb { | |
− | + | // определена g(a) | |
− | + | namespace spbtele { | |
− | + | // вызываем g(a,b) | |
− | namespace spb | + | } |
− | + | } | |
− | + | namespace msk {} | |
− | + | } | |
− | + | </source> | |
− | + | ||
− | namespace msk{} | + | |
− | + | ||
− | + | ||
− | + | ||
− | Чтобы избежать такое, надо в spb записать | + | В предыдущем примере поиск остановиться в spb. Поскольку там тоже есть g. Чтобы избежать такое, надо в spb записать: |
+ | <source lang="cpp"> | ||
using ::Ru::g; | using ::Ru::g; | ||
+ | </source> | ||
− | + | НЕ НАДО=НЕЛЬЗЯ писать using namespaсe std; | |
− | + | Безымянный namespace: | |
− | + | <source lang="cpp"> | |
+ | namespace { | ||
+ | struct test { | ||
+ | ... | ||
+ | }; | ||
+ | } | ||
+ | </source> | ||
− | + | Появится уникальный namespace для каждого .cpp файла. Это позвляет создавать маленькие структуры, не боясь перекрытия имен. Компилятор авторматически добавит после него: | |
− | + | ||
− | + | <source lang="cpp"> | |
+ | using namespace <name>; | ||
+ | </source> | ||
− | + | Пространствам имён можно задавать псевдонимы: | |
+ | <source lang="cpp"> | ||
+ | namespace a = ru::spb::au; | ||
+ | a::f(); | ||
+ | </source> | ||
− | ADL | + | ADL - argument dependent lookup: |
− | + | <source lang="cpp"> | |
− | + | namespace g { | |
− | + | struct complex {}; | |
− | + | complex operator+(); | |
− | + | } | |
− | + | g::complex a, b; | |
− | + | a = a + b; //как ни странно, это сработает :) | |
+ | а = g::operator+(a, b); | ||
+ | </source> | ||
− | Поиск | + | Поиск имён происходит там, где мы находимся, а также и в namespace аргументов (это первый шаг). Этот поиск называется поиском Кёнига. |
− | + | ||
− | + |
Текущая версия на 02:04, 11 июня 2012
Функторы
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)
namespace 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 аргументов (это первый шаг). Этот поиск называется поиском Кёнига.