l = lambda a, b: a + b print l(4, 5) res = sorted([4, -5, 1, -2, -8, 7], cmp=lambda x, y: abs(y) - abs(x)) print resWynik:
9 [-8, 7, -5, 4, -2, 1]
ekstaza, geniusz, przebłysk, olśnienie, półprawdy, półśrodki, przemilczenia, zaćmienia, głupstwa, kłamstewka, oszustwa, hultajstwo, wyrachowanie, nieprawda, nieobiektywność, niepodważalna prawda, nierówność, nieomylność, słuszność, perfekcja, krnąbrność ... niegodziwość
l = lambda a, b: a + b print l(4, 5) res = sorted([4, -5, 1, -2, -8, 7], cmp=lambda x, y: abs(y) - abs(x)) print resWynik:
9 [-8, 7, -5, 4, -2, 1]
gen_expression = (val for val in [1, 2, 3, 4, 7] if val % 2)
try:
print gen_expression.next()
print next(gen_expression)
print gen_expression.next()
print gen_expression.next()
except StopIteration:
print 'Dostalem wyjatek'
Wynik:1 3 7 Dostalem wyjatekDrugim rodzajem generatora jest generator function, który wygląda jak zwykła funkcja. Pozwala jednak na korzystanie mechanizmu yield. W momencie, gdy metoda trafi na takie miejsce, jej działanie jest przerywane i zwracana jest kontrola do naszej części kodu.
def gen_fun(arg = 1):
num = 0
yield num
while True:
num += arg
yield num
yield -num
# Zwraca generator object
g = gen_fun()
print [g.next() for _ in xrange(15)]
Wynik:[0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7]Możemy również przekazać jakąś wartość do wnętrza generatora. W tym celu należy skorzystać z metody send(), które tak jak next() wznawia jego działanie. Jeżeli na takim generatorze zawołamy tylko next(), do środka przekazana zostanie wartość None.
def gen():
arg = 1
num = 0
while True:
num += arg
a = yield num
if a is not None:
arg = a
g = gen()
print g.next()
print g.next()
print g.send(100)
print g.next()
Wynik:1 2 102 202
#include <iostream>
#include <string>
using namespace std;
int main()
{
for (const auto& ch : string("rozciaganie"))
cout << ch << " ";
cout << endl;
return 0;
}
Wynik:r o z c i a g a n i e
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {1, 2, 4, 6};
auto vit = v.begin();
cout << *vit << endl;
return 0;
}
Drugim ficzerem jest detekcja typu przy pomocy decltype. Na podstawie zadanej zmiennej lub wyrażenia odgaduje typ, który będzie nadany nowej zmiennej. W przypadku wyrażenie, nie dochodzi do ewaluacji, wyciągany jest jedynie zwracany typ. Warto też pamiętać, że jeżeli wsadzimy do decltype zmienną i ujmiemy ją w dodatkowe nawiasy, typ który dostaniemy zawsze będzie referencją, a nowa zmienna będzie musiała być zainicjalizowana. Jeżeli natomiast z nawiasów nie skorzystamy to referencję uzyskamy tylko, gdy sama zmienna będzie typem referencyjnym.#include <iostream>
#include <vector>
#include <list>
#include <boost/type_index.hpp>
using namespace std;
list<double>::iterator get_it(list<double> l)
{
return l.begin();
}
int main()
{
list<double> l = {7.1, 2.3, 4.6};
decltype(get_it(l)) it = get_it(l); // list<double>::iterator it = get_it(l);
cout << boost::typeindex::type_id_with_cvr<decltype(it)>().pretty_name() << " " << *it << endl;
int i = 879;
decltype((i)) var1 = i; // int& var1 = i;
cout << boost::typeindex::type_id_with_cvr<decltype(var1)>().pretty_name() << " " << var1 << endl;
int& j = i;
decltype(j) var2 = i; // int& var2 = i;
cout << boost::typeindex::type_id_with_cvr<decltype(var2)>().pretty_name() << " " << var2 << endl;
decltype(i) br = 54; // int br = 54;
cout << boost::typeindex::type_id_with_cvr<decltype(br)>().pretty_name() << " " << br << endl;
return 0;
}
Wyniki:std::_List_iterator<double> 7.1 int& 879 int& 879 int 54
int i, *ip = nullptr; // i jest typu int, ip jest wskaźnikiem na int.
int* p1, p2; // p1 jest wskaźnikiem na int, p2 jest typu int.
int* a, &b = *ip; // a jest wskaźnikiem na int, b jest referencją na wartość
// wskazywaną przez ip.
A teraz trochę o const. Zawsze jest to dla mnie mylące, przynajmniej po dłuższym okresie czasu, gdy wiedza powolutku wyparowuje.const int c = 8; // c jest stałą typu int, jego wartość nie może być zmieniona.
const int &r = c; // ok, referencja na stały obiekt typu int - mówimy co będziemy mogli
// robić przy pomocy referencji - odwołując się do r nie damy rady
// zmodyfikować c (chociaż sam w sobie nie jest const).
int &r2 = c; // error, referencja na niestały obiekt.
Nie ma czegoś takiego jak stałe referencje (z technicznego punktu widzenia), są tylko referencje na stałe. Ponieważ nie można zmusić referencji by wskazywała na inny obiekt w jakimś sensie wszystkie referencje są stałe.double dval = 3.14; const double *pt = &dval; // ok (tak jak wyżej), ale nie możemy zmieniać dval, przy pomocy ptA teraz co powstanie, gdy const znajdzie się w różnych miejscach? Pewne oznaczenia - cytując za książką:
Używamy terminu top-level const do oznaczenia, że sam wskaźnik jest stały. Kiedy wskaźnik może wskazywać na stały obiekt, odnosimy się do tego jako low-level const
int i = 0;
const int c1 = 88; // c1 jest stałym obiektem typu int
int const c2 = 99; // (TO SAMO) c2 jest stałym obiektem typu int
int *const p1 = &i; // p1 jest stałym wskaźnikiem na obiekt typu int (top-level const).
const int ci = 42; // ci jest stałym obiektem typu int (top-level const).
const int *p2 = &ci; // p2 jest wskaźnikiem na stały obiekt typu int (low-level).
int const *p3 = &ci; // (TO SAMO) p3 jest wskaźnikiem na stały obiekt typu int.
const int *const p4 = p2; // p3 jest stałym wskaźnikiem na stały obiekt typu int
// (prawy const jest top-level; lewy nie)
const int &r = i; // referencja na stały obiekt typu int.
// const w typach referencyjnych zawsze jest low-level.
W odróżnieniu od referencji, wskaźniki są obiektami, więc mogą być const, co znaczy, że po ustawieniu w momencie inicjalizacji nie mogą na nic innego wskazywać. #include <iostream>
#include <stdio.h>
using namespace std;
constexpr int get_size()
{
return 6;
}
int main()
{
constexpr int sz = get_size() + 80; // ok, pod warunkiem, że funkcja też jest constexpr.
printf("%d", sz);
return 0;
}
I podgląd tego co wyprodukował kompilator (g++ -std=c++17 -S -masm=intel main.cpp). Jak widać w pliku binarnym pojawia się już obliczona wartość (80+6=86).main:
.LFB1824:
.cfi_startproc
endbr64
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
sub rsp, 16
mov DWORD PTR -4[rbp], 86
mov esi, 86
lea rdi, .LC0[rip]
mov eax, 0
call printf@PLT
mov eax, 0
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
svn co http://llvm.org/svn/llvm-project/llvm/tags/RELEASE_30/final llvm cd llvm/tools svn co http://llvm.org/svn/llvm-project/cfe/tags/RELEASE_30/final clang cd ../.. cd llvm/projects svn co http://llvm.org/svn/llvm-project/llvm/tags/RELEASE_30/final/projects compiler-rt cd ../.. cd llvm/tools/clang/tools svn co http://include-what-you-use.googlecode.com/svn/tags/clang_3.0/ include-what-you-use cd .. # Wyedytować tools/clang/tools/Makefile i dodać include-what-you-use do zmiennej DIRS # Wyedytować tools/clang/tools/CMakeLists.txt i dodać add_subdirectory(include-what-you-use) cd ../../.. # Aby nie zaśmiecać, tworzymy katalog specjalnie na build (nie będzie make install) mkdir build cd build ../llvm/configure makeNiestety, dla mojego testowego projektu, działanie programu kończy się błędem (co jest oczekiwane - nie wiem, tylko czy to ma być taki błąd), i nie generuje raportu.
make -k CXX=~/build/Debug/bin/include-what-you-use > logKu pamięci, mam nadzieje, że wrócę jeszcze kiedyś do tematu.
#ifndef SECOND_HPP
#define SECOND_HPP
#include <iostream>
using namespace std;
namespace bbb
{
namespace
{
int b = 77;
}
class Klasa {
public:
void count2();
};
}
#endif // SECOND_HPP
Plik Second.cpp:#include <vector>
#include <boost/assign/list_of.hpp>
#include "Second.hpp"
namespace bbb
{
namespace
{
int value = 2;
bool isEven(int i) {
return (i == value);
}
}
void Klasa::count2() {
vector<int> v = boost::assign::list_of(1)(2)(3)(2)(1)(1);
cout << "call bbb::Klasa::count2() = " << count_if(begin(v), end(v), isEven) << endl;
}
}
Plik main.cpp:#include <iostream>
#include "Second.hpp"
using namespace std;
namespace std
{
void moja() {
cout << "call std::moja()" << endl;
}
}
namespace aaa
{
namespace
{
std::string a = "asdf";
void access() {
cout << "call aaa::anonymous::access()" << endl;
}
}
void show() {
cout << "call aaa::show()" << endl;
access();
}
}
int main()
{
std::moja();
aaa::access();
aaa::show();
bbb::Klasa s;
s.count2();
// bool l = bbb::isEven(4); // ERROR!
cout << "Access to member aaa::a = " << aaa::a << endl;
cout << "Access to member bbb::b = " << bbb::b << endl;
// cout << "Access to member bbb::value = " << bbb::value << endl; // ERROR!
return 0;
}
Wyniki:call std::moja() call aaa::anonymous::access() call aaa::show() call aaa::anonymous::access() call bbb::Klasa::count2() = 2 Access to member aaa::a = asdf Access to member bbb::b = 77