Ниже представлен пример использования рекурсии с использованием лямбда-выражения
#include <iostream>
#include <functional>
// recursive print function
std::function<void (const std::string&, int)> print = [&] (const std::string& str, int times) {
std::cout << str;
if (times > 1) print(str, times - 1);
};
int main() {
print("!", 5); // !!!!!
return 0;
}
В данном примере в лямбда-выражении в списке захвата задан неявный захват по ссылке без которого Вы получите ошибку времени компиляции. Если Вам необходимо ограничить область захвата, тогда можно уточнить сие в списке захвата:
std::function<void (const std::string&, int)> print = [&print] (const std::string& str, int times) {
std::cout << str << std::endl;
if (times > 1) print(str, times - 1);
};
Где этим можно воспользоваться, ведь намного эффективней явно определить такого рода рекурсивную функцию:
void print(const std::string& str, int n = 1) {
std::cout << str;
if (n > 1) print(str, n - 1);
};
Все конечно зависит от задачи и Вашей фантазии. Ниже приведен один пример, где использован данный подход для сохранения общего интерфейса функций сортировки:
#include <iostream>
#include <vector>
#include <functional>
namespace util {
using namespace std;
void selection_sort(vector<int>& vec, int len);
void insertion_sort(vector<int>& vec, int len);
void bubble_sort(vector<int>& vec, int len);
void quick_sort(vector<int>& vec, int len) {
std::function<void (vector<int>&, int, int)> sorter = [&] (vector<int>& vec, int l, int r) {
int x = vec[l + (r - l) / 2];
int i = l;
int j = r;
while(i <= j) {
while(vec[i] < x) i++;
while(vec[j] > x) j--;
if (i <= j) {
swap(vec[i], vec[j]);
i++;
j--;
}
}
if (i < r) sorter(vec, i, r);
if (l < j) sorter(vec, l, j);
};
sorter(vec, 0, len - 1);
}
}
int main() {
std::vector<int> numbers = {10, 1, 9, 2, 8, 3, 7, 4, 6, 5};
util::quick_sort(numbers, numbers.size()); // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
return 0;
}
PLSQL. Bitwise operations
В plsql отсутствует нативная поддержка побитовых операций, кроме одной - bitand. При необходимости данную возможность можно реализовать самостоятельно. Ниже приведен пример реализации побитового OR и побитового XOR:
-- bit or
function bitor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y);
end;
-- bit xor
function bitxor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y) * 2;
end;
Для реализации операций побитовых сдвигов можно воспользоваться следующим подходом:
declare
-- convert binary to decimal
function bin2dec(binval in varchar2) return number
is
l_digits number;
l_curr_digit char(1);
l_curr_digit_dec number;
l_result number := 0;
begin
l_digits := length(binval);
for i in 1..l_digits loop
l_curr_digit := substr(binval, i, 1);
l_curr_digit_dec := to_number(l_curr_digit);
l_result := (l_result * 2) + l_curr_digit_dec;
end loop;
return l_result;
end;
-- convert decimal to binary
function dec2bin(p_num number) return varchar2
is
binval varchar2(64);
l_num number := p_num;
begin
while (l_num > 0) loop
binval := mod(l_num, 2) || binval;
l_num := trunc(l_num / 2);
end loop;
return binval;
end;
-- bitwise >> for binary
function bin_shift_right(p_bin in varchar2, p_shift in number default null) return varchar2
is
l_length number;
l_shift number;
begin
l_length := length(p_bin);
l_shift := nvl(p_shift, 1);
if (l_length <= 0) then
return null;
end if;
if (l_shift > l_length) then
l_shift := l_length;
end if;
return lpad(substr(p_bin, 1, l_length - l_shift), l_length, '0');
end;
-- bitwise >> for decimal
function shift_right(p_num in number, p_shift in number default null) return number
is
begin
if (trunc(p_num) <> p_num or p_num < 0) then
raise program_error;
end if;
return nvl(bin2dec(bin_shift_right(dec2bin(p_num), p_shift)), 0);
end;
begin
dbms_output.put_line(bin2dec('1000')); -- 8
dbms_output.put_line(shift_right(8, 1)); -- 4
dbms_output.put_line(dec2bin(shift_right(8, 1))); -- 100
end;
Ниже приведен пример использования побитовых операций для контроля возникающих в приложении ошибок:
declare
-- errors bit
ERROR_FIRST constant integer := 1; -- 0001
ERROR_SECOND constant integer := 2; -- 0010
ERROR_THIRD constant integer := 4; -- 0100
ERROR_FOURTH constant integer := 8; -- 1000
-- for capturing errors
l_errors number := 0;
-- bit or
function bitor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y);
end;
-- bit xor
function bitxor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y) * 2;
end;
-- set error bit
procedure set_error(p_errors in out number, p_error number)
is
begin
p_errors := bitor(p_errors, p_error);
end;
-- check if given error captured
function check_error(p_errors in number, p_error number) return boolean
is
begin
return bitand(p_errors, p_error) = p_error;
end;
-- print all captured errors
procedure print_errors(p_errors in number)
is
l_err varchar2(4000) := 'Catched errors:';
begin
if (check_error(p_errors, ERROR_FIRST)) then
l_err := l_err || ' ERROR_FIRST,';
end if;
if (check_error(p_errors, ERROR_SECOND)) then
l_err := l_err || ' ERROR_SECOND,';
end if;
if (check_error(p_errors, ERROR_THIRD)) then
l_err := l_err || ' ERROR_THIRD,';
end if;
if (check_error(p_errors, ERROR_FOURTH)) then
l_err := l_err || ' ERROR_FOURTH,';
end if;
dbms_output.put_line(l_err);
end;
begin
set_error(l_errors, ERROR_FIRST);
set_error(l_errors, ERROR_FOURTH);
print_errors(l_errors);
end;
-- bit or
function bitor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y);
end;
-- bit xor
function bitxor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y) * 2;
end;
Для реализации операций побитовых сдвигов можно воспользоваться следующим подходом:
declare
-- convert binary to decimal
function bin2dec(binval in varchar2) return number
is
l_digits number;
l_curr_digit char(1);
l_curr_digit_dec number;
l_result number := 0;
begin
l_digits := length(binval);
for i in 1..l_digits loop
l_curr_digit := substr(binval, i, 1);
l_curr_digit_dec := to_number(l_curr_digit);
l_result := (l_result * 2) + l_curr_digit_dec;
end loop;
return l_result;
end;
-- convert decimal to binary
function dec2bin(p_num number) return varchar2
is
binval varchar2(64);
l_num number := p_num;
begin
while (l_num > 0) loop
binval := mod(l_num, 2) || binval;
l_num := trunc(l_num / 2);
end loop;
return binval;
end;
-- bitwise >> for binary
function bin_shift_right(p_bin in varchar2, p_shift in number default null) return varchar2
is
l_length number;
l_shift number;
begin
l_length := length(p_bin);
l_shift := nvl(p_shift, 1);
if (l_length <= 0) then
return null;
end if;
if (l_shift > l_length) then
l_shift := l_length;
end if;
return lpad(substr(p_bin, 1, l_length - l_shift), l_length, '0');
end;
-- bitwise >> for decimal
function shift_right(p_num in number, p_shift in number default null) return number
is
begin
if (trunc(p_num) <> p_num or p_num < 0) then
raise program_error;
end if;
return nvl(bin2dec(bin_shift_right(dec2bin(p_num), p_shift)), 0);
end;
begin
dbms_output.put_line(bin2dec('1000')); -- 8
dbms_output.put_line(shift_right(8, 1)); -- 4
dbms_output.put_line(dec2bin(shift_right(8, 1))); -- 100
end;
Ниже приведен пример использования побитовых операций для контроля возникающих в приложении ошибок:
declare
-- errors bit
ERROR_FIRST constant integer := 1; -- 0001
ERROR_SECOND constant integer := 2; -- 0010
ERROR_THIRD constant integer := 4; -- 0100
ERROR_FOURTH constant integer := 8; -- 1000
-- for capturing errors
l_errors number := 0;
-- bit or
function bitor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y);
end;
-- bit xor
function bitxor(x number, y number) return number
is
begin
return (x + y) - bitand(x, y) * 2;
end;
-- set error bit
procedure set_error(p_errors in out number, p_error number)
is
begin
p_errors := bitor(p_errors, p_error);
end;
-- check if given error captured
function check_error(p_errors in number, p_error number) return boolean
is
begin
return bitand(p_errors, p_error) = p_error;
end;
-- print all captured errors
procedure print_errors(p_errors in number)
is
l_err varchar2(4000) := 'Catched errors:';
begin
if (check_error(p_errors, ERROR_FIRST)) then
l_err := l_err || ' ERROR_FIRST,';
end if;
if (check_error(p_errors, ERROR_SECOND)) then
l_err := l_err || ' ERROR_SECOND,';
end if;
if (check_error(p_errors, ERROR_THIRD)) then
l_err := l_err || ' ERROR_THIRD,';
end if;
if (check_error(p_errors, ERROR_FOURTH)) then
l_err := l_err || ' ERROR_FOURTH,';
end if;
dbms_output.put_line(l_err);
end;
begin
set_error(l_errors, ERROR_FIRST);
set_error(l_errors, ERROR_FOURTH);
print_errors(l_errors);
end;
C++. Empty base optimization (EBO, ECBO)
Рассмотрим элиминацию (оптимизацию) пустого базового класса на примере двух классов Foo и Bar:
class Foo {};
class Bar {
Foo f;
int i;
};
Класс Foo является пустым. Как известно, размер любого объекта пустого класса как - минимум - равен 1 байту (для большинства компиляторов):
sizeof(Foo) == 1
Это достигается молчаливой вставкой компилятором одного байта (char) в такой пустой объект. Теперь посмотрим на размер класса Bar:
sizeof(Bar) == 2 * sizeof(int)
В данном случае объект класса Foo занимает 1 байт с выравниванием до размера члена i sizeof(int). Это связано с тем, что два базовых подобъекта одного типа должны иметь разные адреса.
Теперь организуем класс Bar с помощью наследования следующим образом:
class Bar : public Foo {
int i;
};
И снова посмотрим на размер класса Bar:
sizeof(Bar) == sizeof(int)
В итоге мы видим, что компилятор при таком раскладе под подобъект Foo выделил 0 байт. В этом и состоит идея оптимизации пустого базового класса. В стандарте по этому поводу сказано:
Что мы и видим на деле. Всем успехов.
class Foo {};
class Bar {
Foo f;
int i;
};
Класс Foo является пустым. Как известно, размер любого объекта пустого класса как - минимум - равен 1 байту (для большинства компиляторов):
sizeof(Foo) == 1
Это достигается молчаливой вставкой компилятором одного байта (char) в такой пустой объект. Теперь посмотрим на размер класса Bar:
sizeof(Bar) == 2 * sizeof(int)
В данном случае объект класса Foo занимает 1 байт с выравниванием до размера члена i sizeof(int). Это связано с тем, что два базовых подобъекта одного типа должны иметь разные адреса.
Теперь организуем класс Bar с помощью наследования следующим образом:
class Bar : public Foo {
int i;
};
И снова посмотрим на размер класса Bar:
sizeof(Bar) == sizeof(int)
В итоге мы видим, что компилятор при таком раскладе под подобъект Foo выделил 0 байт. В этом и состоит идея оптимизации пустого базового класса. В стандарте по этому поводу сказано:
A class with an empty sequence of [data] members and base class objects is an empty class. Complete objects and member subobjects of an empty class type shall have nonzero size.
Что мы и видим на деле. Всем успехов.
C++. Override and overload
Ниже рассмотрены случаи перекрытия (override) и перегрузки (overload) на примере двух классов Account и Deposit:
class Account {
// ...
void display(const char *fmt);
void display(const int mode = 0);
};
class Deposit : public Account {
// ...
void display(const std::string &fmt);
};
В данном случае одноименный метод display в производном классе Deposit
перекрывает (override) методы базового класса Account, таким образом
методы базового и производного классов не образуют множество перегруженных
функций.
Использование в производном классе объявления using вводит именованный
член базового класса в область видимости производного, тем самым перегружая (overload)
одноименный метод display позволяя создать единое множество перегруженных функций базового и производного классов.
class Account {
// ...
void display(const char *fmt);
void display(const int mode = 0);
};
class Deposit : public Account {
// ...
void display(const std::string &fmt);
using Account::display;
};
В виде примечания в Java понятие перекрытия существует только если у одноименных методов идентичны их сигнатуры, в остальном все методы перегружаются создавая единое множество перегруженных методов базового и производного классов:
class Account {
public void display(char fmt) {
// ...
}
public void display(int mode) {
// ...
}
}
class Deposit extends Account {
public void display(String fmt) {
// ...
}
// ...
}
Также стоит упомянуть о новом синтаксисе C++11 - использование спецификатора override. Использование данного спецификатора гарантирует, что функция 1) - является виртуальной и 2) перекрывает виртуальную функцию базового класса с идентичной ей сигнатурой:
class Alpha {
public:
virtual void foo();
void bar();
};
class Beta : public Alpha {
public:
void foo() override; // допустимо
// void foo() const override; // недопустимо
// void bar() override; // недопустимо
};
class Account {
// ...
void display(const char *fmt);
void display(const int mode = 0);
};
class Deposit : public Account {
// ...
void display(const std::string &fmt);
};
В данном случае одноименный метод display в производном классе Deposit
перекрывает (override) методы базового класса Account, таким образом
методы базового и производного классов не образуют множество перегруженных
функций.
Использование в производном классе объявления using вводит именованный
член базового класса в область видимости производного, тем самым перегружая (overload)
одноименный метод display позволяя создать единое множество перегруженных функций базового и производного классов.
class Account {
// ...
void display(const char *fmt);
void display(const int mode = 0);
};
class Deposit : public Account {
// ...
void display(const std::string &fmt);
using Account::display;
};
В виде примечания в Java понятие перекрытия существует только если у одноименных методов идентичны их сигнатуры, в остальном все методы перегружаются создавая единое множество перегруженных методов базового и производного классов:
class Account {
public void display(char fmt) {
// ...
}
public void display(int mode) {
// ...
}
}
class Deposit extends Account {
public void display(String fmt) {
// ...
}
// ...
}
Также стоит упомянуть о новом синтаксисе C++11 - использование спецификатора override. Использование данного спецификатора гарантирует, что функция 1) - является виртуальной и 2) перекрывает виртуальную функцию базового класса с идентичной ей сигнатурой:
class Alpha {
public:
virtual void foo();
void bar();
};
class Beta : public Alpha {
public:
void foo() override; // допустимо
// void foo() const override; // недопустимо
// void bar() override; // недопустимо
};
Subscribe to:
Posts
(
Atom
)