Та самая презентация
Докладчик: Я
Краткое введение в С++ для java программистов
Краткое введение в С++ для java программистов
Циклы, условия, математические операции, функции - как в java.
Объявления классов почти как в java.
int s = 0;
for (int i =0; i < n; ++i) {
s += i;
}
int s = 0;
vector<int> v {1, 2, 3, 4};
for (auto i: v) {
s += o;
}
class A {
public:
int a;
double b;
private:
float c;
};
+ есть возможность объявлять функции вне классов
Краткое введение в С++ для java программистов
Все типы как примитивные в Java (даже классы)
class A {
char c;
int a;
};
Тип со "звездочкой" - адрес участка памяти в котором находится объект
0x0000
0x07BF
0x07BF
A
c
a
A*
void f() {
A obj;
A* obj_ptr = &obj;
}
Краткое введение в С++ для java программистов
class A {
char c;
int a;
};
Указатели могут указывать на множество объектов
0x0000
0x07BF
0x07BF
A
c
a
A*
void f() {
A obj;
A* obj_ptr = &obj;
}
A
c
a
A
c
a
Краткое введение в С++ для java программистов
Коллекции
list
vector
set
unordered_set
map
unordered_map
LinkedList
ArrayList
TreeSet
HashSet
TreeMap
HashMap
Краткое введение в С++ для java программистов
Алгоритмы
Алгоритмы реализованы отдельно от хранилища и принимают на вход "итераторы"
template< class InputIt, class OutputIt >
OutputIt copy( InputIt first, InputIt last, OutputIt d_first );
template< class RandomIt >
void sort( RandomIt first, RandomIt last );
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
0x0000
first
last
generics vs templates
Классы
Функции
public class Box<T> {
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
java
C++
template <typename T> class Box {
T t_;
public:
void set(const T &t) {t_ = t;}
T get() const { return t_; }
};
public static < E >
void printArray( List<E> inputArray ) {
for(E element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println();
}
template <typename T>
void printArray(const T &inputArray) {
for (auto const &element : inputArray) {
std::cout << element << " ";
}
std::cout << std::endl;
}
java
C++
generics vs templates
Различия
- Интерфейс vs Кодогенерация
- Базовые типы в шаблонах
- Специализация
generics vs templates
Интерфейс vs Кодогенерация
generics vs templates
public static < T >
void f( T t ) {
System.out.printf("%s ", t.size());
}
Error:(5, 35) java: cannot find symbol
symbol: method size()
location: variable t of type T
java
Интерфейс vs Кодогенерация
generics vs templates
public static < T >
void f( T t ) {
System.out.printf("%s ", t.size());
}
Error:(5, 35) java: cannot find symbol
symbol: method size()
location: variable t of type T
interface Sizable {
int size();
}
public static < T extends Sizable >
void f( T t ) {
System.out.printf("%s ", t.size());
}
java
Интерфейс vs Кодогенерация
generics vs templates
public static < T >
void f( T t ) {
System.out.printf("%s ", t.size());
}
Error:(5, 35) java: cannot find symbol
symbol: method size()
location: variable t of type T
interface Sizable {
int size();
}
public static < T extends Sizable >
void f( T t ) {
System.out.printf("%s ", t.size());
}
java
template<typename T>
void f(T t) {
cout << t.size() << endl;
}
C++
Интерфейс vs Кодогенерация
generics vs templates
Интерфейс vs Кодогенерация
public static < T >
void f( T t ) {
System.out.printf("%s ", t.size());
}
Error:(5, 35) java: cannot find symbol
symbol: method size()
location: variable t of type T
interface Sizable {
int size();
}
public static < T extends Sizable >
void f( T t ) {
System.out.printf("%s ", t.size());
}
java
template<typename T> void f(T t) {
cout << t.size() << endl;
}
struct S {
string size() {
return "Never ask me about my size!";
}
};
int main() {
f(S());
vector<int> v(5);
f(v);
v.push_back(5);
f(v);
}
C++
template<> void f(vector<int> t) {
cout << t.size() << endl;
}
template<> void f(S t) {
cout << t.size() << endl;
}
generics vs templates
Интерфейс vs Кодогенерация
public static < T >
void f( T t ) {
System.out.printf("%s ", t.size());
}
Error:(5, 35) java: cannot find symbol
symbol: method size()
location: variable t of type T
interface Sizable {
int size();
}
public static < T extends Sizable >
void f( T t ) {
System.out.printf("%s ", t.size());
}
java
template<typename T> void f(T t) {
cout << t.size() << endl;
}
struct S {
string size() {
return "Never ask me about my size!";
}
};
int main() {
f(S());
vector<int> v(5);
f(v);
v.push_back(5);
f(v);
}
C++
Never ask me about my size!
5
6
generics vs templates
template<typename T> void f(T t) {
cout << t.size() << endl;
}
struct None {};
static None none;
int main() {
f(none);
}
C++
./intro.cpp: In instantiation of ‘void f(T) [with T = None]’:
./intro.cpp:56:9: required from here
./intro.cpp:23:13: error: ‘struct None’ has no member named ‘size’
std::cout << t.size() << std::endl;
^
"Неявный контракт":
template<typename T> void f(T t) {
cout << t.size() << endl;
}
struct S {
string size() {
return "Never ask me about my size!";
}
};
int main() {
f(S());
}
Интерфейс vs Кодогенерация
generics vs templates
Кодогенерация
Плюсы:
- Неявные зависимости
- Большая гибкость
- Нет нагрузки на рантайм за счет полиморфизма
Минусы:
- Неявные зависимости
- Нельзя скомпилировать заранее
- Сложно для IDE
generics vs templates
Базовые типы в шаблонах
generics vs templates
Базовые типы в шаблонах
template <int Index, typename Coll> int array_at(const Coll &v) {
return v[Index];
}
int main() {
std::vector<int> v(3);
for (auto i : {1, 2, 3}) {
v[i] = i;
}
std::cout << array_at<0>(v) << std::endl;
std::cout << array_at<1>(v) << std::endl;
std::cout << array_at<2>(v) << std::endl;
return 0;
}
0
1
2
generics vs templates
Базовые типы в шаблонах
template< std::size_t N >
class bitset;
int main()
{
std::bitset<8> b1; // [0,0,0,0,0,0,0,0]
std::bitset<8> b2(42); // [0,0,1,0,1,0,1,0]
for (std::size_t i = 0; i < b1.size(); ++i) {
std::cout << "b2[" << i << "]: " << b2[i] << '\n';
}
}
b1[0]: 0
b1[1]: 1
b1[2]: 0
b1[3]: 1
b1[4]: 0
b1[5]: 1
b1[6]: 0
b1[7]: 0
generics vs templates
Базовые типы в шаблонах
template <intmax_t N, intmax_t D = 1> class ratio;
int main ()
{
typedef ratio<1,3> one_third;
typedef ratio<2,4> two_fourths;
cout << "one_third= " << one_third::num << "/" << one_third::den << endl;
cout << "two_fourths= " << two_fourths::num << "/" << two_fourths::den << endl;
typedef ratio_add<one_third,two_fourths> sum;
cout << "sum= " << sum::num << "/" << sum::den;
}
one_third= 1/3
two_fourths= 1/2
sum= 5/6
generics vs templates
Базовые типы в шаблонах
typedef ratio<1, 1000000> micro;
typedef ratio<1, 1000> milli;
typedef ratio<1, 100> centi;
typedef ratio<1, 10> deci;
typedef ratio< 10, 1> deca;
typedef duration<int64_t, micro> microseconds;
typedef duration<int64_t, milli> milliseconds;
typedef duration<int64_t> seconds;
typedef duration<int64_t, ratio< 60>> minutes;
typedef duration<int64_t, ratio<3600>> hours;
generics vs templates
Policies
(in next theme)
generics vs templates
Специализация
generics vs templates
Специализация
template<typename T> void f(T t) {
cout << t.size() << endl;
}
struct S {
string size() {
return "Kind of a size";
}
};
struct None {};
int main() {
f(S());
// f(None); // Compilation error
}
Kind of a size
generics vs templates
Специализация
template<typename T> void f(T t) {
cout << t.size() << endl;
}
struct S {
string size() {
return "Kind of a size";
}
};
struct None {};
int main() {
f(S());
// f(None); // Compilation error
}
Kind of a size
template<typename T> void f(T t) {
cout << t.size() << endl;
}
struct S {
string size() {
return "Kind of a size";
}
};
struct None {};
template <> void f<None>(None n) {
cout << "None has no size..." << endl;
}
int main() {
f(S());
f(None);
}
Kind of a size
None has no size...
generics vs templates
Специализация
template<typename T>
void algorithm(T t) {
/*
* Some code
*/
}
template<>
void algorithm<MyClass>(MyClass t) {
/*
* Faster realization
*/
}
template<typename T> void f(T t) {
/*
* Some common preprocessing
*/
algorithm(t);
/*
* Some common postprocessing
*/
}
generics vs templates
Специализация
В стандартной библиотеке STL предусмотрена специализация
template<class Allocator>
class vector<bool, Allocator>;
std::vector<bool> is a space-efficient specialization of std::vector for the type bool.
The manner in which std::vector<bool> is made space efficient (as well as whether it is optimized at all) is implementation defined. One potential optimization involves coalescing vector elements such that each element occupies a single bit instead of sizeof(bool) bytes.
generics vs templates
Специализация
temaplte<typename T>
struct S {
vector<T> member;
};
// S s1<bool> -> compact version
// S s1<int> -> ordinal version
temaplte<typename T>
struct S {
vector<T> member;
};
struct SCompact {
BoolVector member;
}
generics vs templates
Специализация
enum class CachePolicy { Cache, NoCache };
template <CachePolicy P = CachePolicy::NoCache>
void optionalCache();
template <>
void optionalCache<CachePolicy::NoCache>() {
std::cout << "Do not cache" << std::endl;
}
template <>
void optionalCache<CachePolicy::Cache>() {
std::cout << "Cache" << std::endl;
}
int main() {
optionalCache();
optionalCache<CachePolicy::Cache>();
}
Do not cache
Cache
generics vs templates
Специализация
template <CachePolicy P = CachePolicy::NoCache>
void imUsingCache() {
// ........
// someCode
// ........
optionalCache<P>();
// ........
// someCode
// ........
}
generics vs templates
Специализация
template<typename T>
struct IsInt {
static const bool value = false;
};
template<>
struct IsInt<int> {
static const bool value = true;
};
int main() {
cout << "Check, is int: " << endl;
cout << IsInt<bool>::value << endl;
cout << IsInt<int>::value << endl;
cout << IsInt<int64_t>::value << endl;
cout << IsInt<int32_t>::value << endl;
}
Check, is int:
0
1
0
1
generics vs templates
Специализация
template<typename T, typename U>
struct IsSame {
static const bool value = false;
};
template<typename T>
struct IsSame<T, T> {
static const bool value = true;
};
int main() {
std::cout << "Check, is same: " << std::endl;
std::cout << IsSame<int32_t, bool>::value << std::endl;
std::cout << IsSame<int32_t, int>::value << std::endl;
std::cout << IsSame<bool, bool>::value << std::endl;
std::cout << IsSame<char, int8_t>::value << std::endl;
}
Check, is same:
0
1
1
0
generics vs templates
Специализация
template <class T, T v> struct integral_constant;
template <bool B>
using bool_constant = integral_constant<bool, B>;
using true_type = bool_constant<true>;
using false_type = bool_constant<false>;
// primary type categories:
template <class T> struct is_void;
template <class T> struct is_null_pointer;
template <class T> struct is_integral;
template <class T> struct is_floating_point;
template <class T> struct is_array;
template <class T> struct is_pointer;
template <class T> struct is_lvalue_reference;
template <class T> struct is_rvalue_reference;
template <class T> struct is_member_object_pointer;
template <class T> struct is_member_function_pointer;
template <class T> struct is_enum;
template <class T> struct is_union;
template <class T> struct is_class;
template <class T> struct is_function;
// composite type categories:
template <class T> struct is_reference;
template <class T> struct is_arithmetic;
template <class T> struct is_fundamental;
template <class T> struct is_object;
template <class T> struct is_scalar;
template <class T> struct is_compound;
template <class T> struct is_member_pointer;
// type properties:
template <class T> struct is_const;
template <class T> struct is_volatile;
template <class T> struct is_trivial;
template <class T> struct is_trivially_copyable;
template <class T> struct is_standard_layout;
template <class T> struct is_pod;
template <class T> struct is_empty;
template <class T> struct is_polymorphic;
template <class T> struct is_abstract;
template <class T> struct is_final;
template <class T> struct is_signed;
template <class T> struct is_unsigned;
template <class T, class... Args> struct is_constructible;
template <class T> struct is_default_constructible;
template <class T> struct is_copy_constructible;
template <class T> struct is_move_constructible;
template <class T, class U> struct is_assignable;
template <class T> struct is_copy_assignable;
template <class T> struct is_move_assignable;
template <class T, class U> struct is_swappable_with;
template <class T> struct is_swappable;
template <class T> struct is_destructible;
template <class T, class... Args> struct is_trivially_constructible;
template <class T> struct is_trivially_default_constructible;
template <class T> struct is_trivially_copy_constructible;
template <class T> struct is_trivially_move_constructible;
template <class T, class U> struct is_trivially_assignable;
template <class T> struct is_trivially_copy_assignable;
template <class T> struct is_trivially_move_assignable;
template <class T> struct is_trivially_destructible;
template <class T> struct is_trivially_destructible;
template <class T, class... Args> struct is_nothrow_constructible;
template <class T> struct is_nothrow_default_constructible;
template <class T> struct is_nothrow_copy_constructible;
template <class T> struct is_nothrow_move_constructible;
template <class T, class U> struct is_nothrow_assignable;
template <class T> struct is_nothrow_copy_assignable;
template <class T> struct is_nothrow_move_assignable;
template <class T, class U> struct is_nothrow_swappable_with;
template <class T> struct is_nothrow_swappable;
template <class T> struct is_nothrow_destructible;
template <class T> struct has_virtual_destructor;
template <class T> struct has_unique_object_representations;
generics vs templates
Специализация
template<bool Cond>
struct StaticAssert;
template<>
struct StaticAssert<true> {};
template<bool Cond>
void assert() {
StaticAssert<Cond> a;
}
int main() {
assert<true>(); // OK
// assert<false>(); // error: ‘StaticAssert<false> a’ has incomplete type
assert<IsSame<int32_t, int>::value>(); // OK
// assert<IsSame<bool, int>::value>(); // error:
// ‘StaticAssert<false> a’ has incomplete type
}
generics vs templates
Специализация
template<class T,class... Args>
typename std::enable_if<std::is_nothrow_constructible<T,Args&&...>::value>::type
construct(T* t,Args&&... args)
{
cout << "constructing trivially constructible T\n";
}
template<class T, class... Args>
std::enable_if_t<!std::is_nothrow_constructible<T,Args&&...>::value>
construct(T* t,Args&&... args)
{
cout << "constructing non-trivially constructible T\n";
new(t, detail::inplace_t{}) T(args...);
}
template<bool B, class T = void> struct enable_if {};
template< bool B, class T = void > |
Пара слов о дизайне приложений
Пара слов о дизайне приложений
- S
- O
- L
- I
- D
Пара слов о дизайне приложений
- S - The Single Responsibility Principle
- O - The Open Closed Principle
- L - The Liskov Substitution Principle
- I - The Interface Segregation Principle
- D - The Dependency Inversion Principle
Пара слов о дизайне приложений
- S - The Single Responsibility Principle
- O - The Open Closed Principle
- L - The Liskov Substitution Principle
- I - The Interface Segregation Principle
- D - The Dependency Inversion Principle
Пара слов о дизайне приложений
The Single Responsibility Principle
Один класс - одна зона ответственности.
Сущаствует ровно одна причина, приводящая к изменению класса.
The Open Closed Principle
Объекты программ должны быть открыты для расширения, но закрыты для модификации.
Пара слов о дизайне приложений
template<typename T>
void algorithm(T t) {
/*
* Some code
*/
}
template<>
void algorithm<A>(A t) {
/*
* Faster realization
*/
}
template<typename T> void f(T t) {
/*
* Some common preprocessing
*/
algorithm(t);
/*
* Some common postprocessing
*/
}
Пара слов о дизайне приложений
template<typename T>
void algorithm(T t) {
/*
* Some code
*/
}
template<>
void algorithm<A>(A t) {
/*
* Faster realization
*/
}
template<typename T> void f(T t) {
/*
* Some common preprocessing
*/
algorithm(t);
/*
* Some common postprocessing
*/
}
class MyNewClass {
// .. members ..
// .. functions ..
};
template<>
void algorithm<MyNewClass>(MyNewClass t) {
/*
* Special realization
*/
}
Пара слов о дизайне приложений
template<typename T>
void algorithm(T t) {
/*
* Some code
*/
}
template<>
void algorithm<A>(A t) {
/*
* Faster realization
*/
}
template<typename T> void f(T t) {
/*
* Some common preprocessing
*/
algorithm(t);
/*
* Some common postprocessing
*/
}
// A --> I
// B --> I
void algorithm(I t) {
/*
* Some code
*/
}
void fast_algorithm(A t) {
/*
* Faster realization
*/
}
void f(I t) {
/*
* Some common preprocessing
*/
if (t isinstanceof A)
fast_algorithm((A)t);
else
algorithm(t);
/*
* Some common postprocessing
*/
}
Пара слов о дизайне приложений
template<typename T>
void algorithm(T t) {
/*
* Some code
*/
}
template<>
void algorithm<A>(A t) {
/*
* Faster realization
*/
}
template<typename T> void f(T t) {
/*
* Some common preprocessing
*/
algorithm(t);
/*
* Some common postprocessing
*/
}
// A --> I
// B --> I
// fast_algorithm(A a)
// algorithm(I i)
void preprocessing(T) {
// ...
}
void postprocessing(T) {
// ...
}
void f(A a) {
preprocessing(a);
fast_algorithm((A)t);
postprocessing(a);
}
void f(B a) {
preprocessing(b);
algorithm(t);
postprocessing(b);
}
Traits
Traits
class Person {};
class Paper {};
template<typename T>
struct SQLTraits;
template<>
struct SQLTraits<Person> {
static const std::string table;
};
const std::string SQLTraits<Person>::table = "person_table";
template<>
struct SQLTraits<Paper> {
static const std::string table;
};
const std::string SQLTraits<Paper>::table = "paper_table";
template<typename T>
void selectAll(T t) {
cout << "Select * from " <<
SQLTraits<decltype(t)>::table << ";" << endl;
}
int main() {
Person psn;
Paper ppr;
selectAll(psn);
selectAll(ppr);
}
Select * from person_table;
Select * from paper_table;
Traits
class Person {};
class Paper {};
template<typename T>
struct SQLTraits;
template<>
struct SQLTraits<Person> {
static const std::string table;
};
const std::string SQLTraits<Person>::table = "person_table";
template<>
struct SQLTraits<Paper> {
static const std::string table;
};
const std::string SQLTraits<Paper>::table = "paper_table";
template<typename T>
void selectAll(T t) {
cout << "Select * from " <<
SQLTraits<decltype(t)>::table << ";" << endl;
}
int main() {
Person psn;
Paper ppr;
selectAll(psn);
selectAll(ppr);
}
Select * from person_table;
Select * from paper_table;
template <typename First, typename... Rest>
void selectAll(First f, Rest... args) {
selectAll(f);
selectAll(args...);
}
Traits
class Person {};
class Paper {};
template<typename T>
struct SQLTraits;
template<>
struct SQLTraits<Person> {
static const std::string table;
};
const std::string SQLTraits<Person>::table = "person_table";
template<>
struct SQLTraits<Paper> {
static const std::string table;
};
const std::string SQLTraits<Paper>::table = "paper_table";
template<typename T>
void selectAll(T t) {
cout << "Select * from " <<
SQLTraits<decltype(t)>::table << ";" << endl;
}
int main() {
Person psn;
Paper ppr;
selectAll(psn);
selectAll(ppr);
}
Select * from person_table;
Select * from paper_table;
template <typename First, typename... Rest>
void selectAll(First f, Rest... args) {
selectAll(f);
selectAll(args...);
}
Select * from person_table;
Select * from paper_table;
Select * from paper_table;
Select * from person_table;
int main() {
Person psn;
Paper ppr;
selectAll(psn, ppr,
ppr, psn);
}
Traits
struct Person {
int id;
};
struct Paper {
int id;
};
struct Session {
Person getPerson(int id) {
cout << "Getting person " << id << endl;
return Person{id};
}
Paper getPaper(int id) {
cout << "Getting paper " << id << endl;
return Paper{id};
}
};
Traits
struct Person {
int id;
};
struct Paper {
int id;
};
struct Session {
Person getPerson(int id) {
cout << "Getting person " << id << endl;
return Person{id};
}
Paper getPaper(int id) {
cout << "Getting paper " << id << endl;
return Paper{id};
}
};
template<typename T>
struct SessionTrait;
template<>
struct SessionTrait<Person> {
constexpr static Person getter
(Session& s, int id) {
return s.getPerson(id);
}
};
template<>
struct SessionTrait<Paper> {
constexpr static Paper getter
(Session& s, int id) {
return s.getPaper(id);
}
};
template <typename T>
T getObject(Session &session, int id) {
return SessionTrait<T>::getter(session, id);
}
Traits
int main() {
Session s;
auto psn = getObject<Person>(s, 1);
auto ppr = getObject<Paper>(s, 2);
}
Getting person 1
Getting paper 2
struct Person {
int id;
};
struct Paper {
int id;
};
struct Session {
Person getPerson(int id) {
cout << "Getting person " << id << endl;
return Person{id};
}
Paper getPaper(int id) {
cout << "Getting paper " << id << endl;
return Paper{id};
}
};
template<typename T>
struct SessionTrait;
template<>
struct SessionTrait<Person> {
constexpr static Person getter
(Session& s, int id) {
return s.getPerson(id);
}
};
template<>
struct SessionTrait<Paper> {
constexpr static Paper getter
(Session& s, int id) {
return s.getPaper(id);
}
};
template <typename T>
T getObject(Session &session, int id) {
return SessionTrait<T>::getter(session, id);
}
Traits
Session
Person
Paper
Trait
Traits
Session
Person
Paper
Trait
template <typename T>
T getObject(Session &session, int id) {
return SessionTrait<T>::getter(session, id);
}
Traits
Session
Person
Paper
Trait
template <typename T>
T getObject(Session &session, int id) {
return SessionTrait<T>::getter(session, id);
}
Bibliography:
- Person
- [Paper, ...]
Traits
Session
Person
Paper
Trait
template <typename T>
T getObject(Session &session, int id) {
return SessionTrait<T>::getter(session, id);
}
Bibliography:
- Person
- [Paper, ...]
template <>
SessionTrait<Bibliography> {
constexpr static Paper getter
(Session& s, int id) {
// Collect elements
}
};
Session s;
auto bbg = getObject<Bibliography>(s, 1);
Iterators
Iterators
Forward iterator
beg
end
Iterators
Forward iterator
beg
end
Bidirectional iterator
beg
end
Iterators
Forward iterator
beg
end
Bidirectional iterator
beg
end
Random access iterator
beg
end
Iterators
Forward iterator
Bidirectional iterator
Random access iterator
T operator*();
void operator++();
T operator*();
void operator++();
void operator--();
T operator*();
void operator++();
void operator--();
void operator+(int);
Iterators
Algorithm | Forward iterator | Bidirectional iterator | Random access iterator |
---|---|---|---|
count | |||
next_permutation | |||
binary_search | |||
sort |
Iterators
interface ForwardIterator {
public ForwardIterator next_forward();
}
abstract class BidirectionalIterator implements ForwardIterator {
public abstract BidirectionalIterator prev_bidirect();
public abstract BidirectionalIterator next_bidirect();
public ForwardIterator next_forward() {
return next_bidirect();
}
}
abstract class RandomAccessIterator extends BidirectionalIterator {
public abstract RandomAccessIterator advance(int n);
public BidirectionalIterator prev_bidirect() {
return advance(-1);
}
public BidirectionalIterator next_bidirect() {
return advance(1);
}
}
java
Iterators
/**
* Change iterator position by n
*/
template<typename Iter, typename Digit>
Iter advance(Iter it, Digit n);
Iterators
struct FwdIterTag {};
struct BidirectIterTag : FwdIterTag {};
struct RandomIterTag : BidirectIterTag{};
template <typename IterTag>
struct AdvanceImpl;
/**
* Change iterator position by n
*/
template<typename Iter, typename Digit>
Iter advance(Iter it, Digit n);
Iterators
struct FwdIterTag {};
struct BidirectIterTag : FwdIterTag {};
struct RandomIterTag : BidirectIterTag{};
template <typename IterTag>
struct AdvanceImpl;
/**
* Change iterator position by n
*/
template<typename Iter, typename Digit>
Iter advance(Iter it, Digit n);
template <> struct AdvanceImpl<RandomIterTag> {
template <typename Iter, typename Distance>
static Iter advance(Iter it, Distance n) {
it += n;
return it;
}
};
Iterators
struct FwdIterTag {};
struct BidirectIterTag : FwdIterTag {};
struct RandomIterTag : BidirectIterTag{};
template <typename IterTag>
struct AdvanceImpl;
/**
* Change iterator position by n
*/
template<typename Iter, typename Digit>
Iter advance(Iter it, Digit n);
template <> struct AdvanceImpl<RandomIterTag> {
template <typename Iter, typename Distance>
static Iter advance(Iter it, Distance n) {
it += n;
return it;
}
};
template <> struct AdvanceImpl<BidirectIterTag> {
template <typename Iter, typename Distance>
static Iter advance(Iter it, Distance n) {
while (n > 0) { ++it; --n; }
while (n < 0) { --it; ++n; }
return it;
}
};
Iterators
struct FwdIterTag {};
struct BidirectIterTag : FwdIterTag {};
struct RandomIterTag : BidirectIterTag{};
template <typename IterTag>
struct AdvanceImpl;
/**
* Change iterator position by n
*/
template<typename Iter, typename Digit>
Iter advance(Iter it, Digit n);
template <> struct AdvanceImpl<RandomIterTag> {
template <typename Iter, typename Distance>
static Iter advance(Iter it, Distance n) {
it += n;
return it;
}
};
template <> struct AdvanceImpl<BidirectIterTag> {
template <typename Iter, typename Distance>
static Iter advance(Iter it, Distance n) {
while (n > 0) { ++it; --n; }
while (n < 0) { --it; ++n; }
return it;
}
};
template <> struct AdvanceImpl<FwdIterTag> {
template <typename Iter, typename Distance>
static Iter advance(Iter it, Distance n) {
if (n < 0) throw "Decrement fwd iter";
while (n > 0) { ++it; --n; }
return it;
}
};
Iterators
struct FwdIterTag {};
struct BidirectIterTag : FwdIterTag {};
struct RandomIterTag : BidirectIterTag {};
template <typename IterTag>
struct AdvanceImpl;
struct MyIter {
typedef RandomIterTag IterTag;
// Realization
// ...
};
template <typename Iter, typename Digit>
Iter advance(Iter it, Digit n) {
AdvanceImpl<typename Iter::IterTag>
::advance(it, n);
}
template <typename Iter>
void sort(Iter first, Iter last) {
// static_assert at least Bidirect
// ... code ...
advance(first, k);
// ... code ...
}
template <> struct AdvanceImpl<RandomIterTag> {
template <typename Iter, typename Distance>
static Iter advance(Iter it, Distance n) {
it += n;
return it;
}
};
template <> struct AdvanceImpl<BidirectIterTag> {
template <typename Iter, typename Distance>
static Iter advance(Iter it, Distance n) {
while (n > 0) { ++it; --n; }
while (n < 0) { --it; ++n; }
return it;
}
};
template <> struct AdvanceImpl<FwdIterTag> {
template <typename Iter, typename Distance>
static Iter advance(Iter it, Distance n) {
if (n < 0) throw "Decrement fwd iter";
while (n > 0) { ++it; --n; }
return it;
}
};
Iterators
template <typename Iter, typename Digit>
Iter advance(Iter it, Digit n) {
AdvanceImpl<typename Iter::IterTag>
::advance(it, n);
}
int* arr = new int[10];
int* third = advance(arr, 3);
Iterators
template <typename Iter, typename Digit>
Iter advance(Iter it, Digit n) {
AdvanceImpl<typename Iter::IterTag>
::advance(it, n);
}
T*
Iterators
template <typename Iter, typename Digit>
Iter advance(Iter it, Digit n) {
AdvanceImpl<typename IteratorTraits<Iter>::IterTag>::advance(it, n);
}
template <typename T> struct IteratorTraits {
typedef typename T::IteratorTag IteratorTag;
};
// Open Closed Principle itself
template <typename T> struct IteratorTraits<T *> {
typedef RandomIterTag IteratorTag;
};
template <typename Iter, typename Digit>
Iter advance(Iter it, Digit n) {
AdvanceImpl<typename Iter::IterTag>::advance(it, n);
}
Iterators
Преимущества выделения трейта:
- Алгоритм не знает о внутреннем устройстве итераторов больше необходимого минимума (SLP)
- Можно зарегистрировать любой класс как итератор не меняя ни код самого класса, ни код библиотеки (OCP)
Преимущества использования тегов вместо наследования
- Нет накладных расходов в рантайме на полиморфизм
Strings
Strings
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
typedef basic_string<char16_t> u16string;
typedef basic_string<char32_t> u32string;
Strings
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
typedef basic_string<char16_t> u16string;
typedef basic_string<char32_t> u32string;
template<typename _CharT,
typename _Traits = char_traits<_CharT>,
typename _Alloc = allocator<_CharT> >
class basic_string;
Strings
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
typedef basic_string<char16_t> u16string;
typedef basic_string<char32_t> u32string;
template<typename _CharT,
typename _Traits = char_traits<_CharT>,
typename _Alloc = allocator<_CharT> >
class basic_string;
template<typename _CharT>
struct char_traits
{
static void assign(char_type& __c1, const char_type& __c2);
static bool eq(const char_type& __c1, const char_type& __c2);
static lt(const char_type& __c1, const char_type& __c2);
static int compare(const char_type* __s1, const char_type* __s2, std::size_t __n);
static std::size_t length(const char_type* __s);
static const char_type* find(const char_type* __s, std::size_t __n, const char_type& __a);
static char_type* move(char_type* __s1, const char_type* __s2, std::size_t __n);
static char_type* copy(char_type* __s1, const char_type* __s2, std::size_t __n);
static char_type* assign(char_type* __s, std::size_t __n, char_type __a);
static char_type to_char_type(const int_type& __c);
static int_type to_int_type(const char_type& __c);
static bool eq_int_type(const int_type& __c1, const int_type& __c2);
static int_type eof();
static int_type not_eof(const int_type& __c);
};
Strings
Задача: написать класс строки с компаратором, не учитывающим регистр.
Strings
Задача: написать класс строки с компаратором, не учитывающим регистр.
struct ci_char_traits : public std::char_traits<char> {
static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
static bool lt(char c1, char c2) { return toupper(c1) < toupper(c2); }
static int compare(const char* s1, const char* s2, size_t n) {
while ( n-- != 0 ) {
if ( toupper(*s1) < toupper(*s2) ) return -1;
if ( toupper(*s1) > toupper(*s2) ) return 1;
++s1; ++s2;
}
return 0;
}
static const char* find(const char* s, int n, char a) {
auto const ua (toupper(a));
while ( n-- != 0 )
{
if (toupper(*s) == ua) return s;
s++;
}
return nullptr;
}
};
Strings
Задача: написать класс строки с компаратором, не учитывающим регистр.
typedef std::basic_string<char, ci_char_traits> ci_string;
std::ostream &operator<<(std::ostream &os, const ci_string &str) {
return os.write(str.data(), str.size());
}
int main() {
ci_string s1 = "Hello";
ci_string s2 = "heLLo";
if (s1 == s2)
std::cout << s1 << " and " << s2 << " are equal\n";
std::vector<ci_string> v{"zVf", "Zvf", "Abs", "abs"};
std::sort(v.begin(), v.end());
for (auto const &s : v) {
std::cout << s << std::endl;
}
}
Hello and heLLo are equal
Abs
abs
zVf
Zvf
Strings
Задача
Strings
struct capcha_traits : public std::char_traits<char> {
static void assign(char &c1, char const &c2) { c1 = std::toupper(c2); }
static char *copy(char *s1, const char *s2, std::size_t n) {
auto end = s2 + n;
for (auto it = s2; it != end; ++it) {
*s1++ = std::toupper(*it);
}
return s1;
}
static char *assign(char *s, std::size_t n, char a) {
std::fill_n(s, n, std::toupper(a));
return s;
}
};
int main() {
capcha name = "Pavel";
capcha sname = "Sukhov";
std::cout << name << "\t" << sname << std::endl;
capcha seq;
for (auto const &c : {'H', 'e', 'l', 'L', 'o'}) {
seq.push_back(c);
}
std::cout << seq << std::endl;
}
Strings
int main() {
capcha name = "Pavel";
capcha sname = "Sukhov";
std::cout << name << "\t" << sname << std::endl;
capcha seq;
for (auto const &c : {'H', 'e', 'l', 'L', 'o'}) {
seq.push_back(c);
}
std::cout << seq << std::endl;
}
PAVEL SUKHOV
HELLO
Strings
Задача: сделать строку, в которой экранируются символы '\'
Strings
Задача: сделать строку, в которой экранируются символы '\'
struct quote_traits : public std::char_traits<char> {
static void assign(char &c1, char const &c2) {
if (c2 == '\\')
throw std::runtime_error("unable to assign '\\'");
c1 = c2;
}
static char *copy(char *s1, const char *s2, std::size_t n) {
auto end = s2 + n;
for (auto it = s2; it != end; ++it) {
if (*it == '\\')
*s1++ = '\\';
*s1++ = *it;
}
return s1;
}
static char *assign(char *s, std::size_t n, char a) {
std::fill_n(s, n, a);
if (a == '\\')
std::fill_n(s, n, a);
return s;
}
};
Strings
Задача: сделать строку, в которой экранируются символы '\'
int main() {
quote to_quote = "Ras\\Dva";
std::cout << to_quote << std::endl;
to_quote[1] = '\\';
std::cout << to_quote << std::endl;
// to_quote.assign(2, '\\'); // Oooops, exception
}
Ras\\Dv
R\s\\Dv
Strings
Задача: сделать строку, в которой экранируются символы '\'
В с++ работает только для символа '\':
В противном случае не гарантируется, что в массиве выделено достаточно памяти!
static void assign(char &c1, char const &c2);
static char *copy(char *s1, const char *s2, std::size_t n);
static char *assign(char *s, std::size_t n, char a);
Strings
Задача: сделать строку, в которой экранируются символы '\'
В с++ работает только для символа '\':
В противном случае не гарантируется, что в массиве выделено достаточно памяти!
static void assign(char &c1, char const &c2);
static char *copy(char *s1, const char *s2, std::size_t n);
static char *assign(char *s, std::size_t n, char a);
template<typename _CharT,
typename _Traits = char_traits<_CharT>,
typename _Alloc = allocator<_CharT> >
class basic_string;
Выделением памяти тоже можно управлять!
Про аллокаторы - следующая тема
Allocators
Allocators
template<
class CharT,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>
> class basic_string;
template<
class T,
class Allocator = std::allocator<T>
> class vector;
template<
class Key,
class T,
class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T> >
> class map;
template<
class Key,
class Compare = std::less<Key>,
class Allocator = std::allocator<Key>
> class set;
Allocators
tbb::scalable_allocator<T>
tbb::cache_aligned_allocator<T>
Intel TBB
Base Allocator
Aligned Allocations
Linear Allocator
Stack Allocator
FreeList Allocator
Pool Allocator
Proxy Allocator
malloc | custom | |
---|---|---|
Linear | 0.639655 | 0.000072 |
Stack | 0.650435 | 0.000289 |
FreeList | 0.673865 | 0.000414 |
Pool | 1.454934 | 0.000193 |
Strings
java
Можно ли сделать аналогичную архитектуру на Java?
Strings
java
interface CharTraits {
int compare(char l, char r);
}
interface CharAllocator {
char[] allocate(int n);
char[] reallocate(char[] source, int n) ;
}
Strings
java
class DefaultCharTraits implements CharTraits {
@Override
public int compare(char l, char r) {
if (l < r) return -1;
else if (r > l) return 1;
else return 0;
}
}
class DefaultAllocator implements CharAllocator {
@Override
public char[] allocate(int n) {
return new char[n];
}
@Override
public char[] reallocate(char[] source, int n) {
char[] arr = new char[n];
System.arraycopy(source, 0, arr, 0, n);
return arr;
}
}
Strings
java
abstract class MyBaseString<Trait extends CharTraits,
Allocator extends CharAllocator> {
private Trait traits_ = new Trait();
private Allocator allocator_ = new Allocator();
}
Strings
import java.lang.reflect.ParameterizedType;
abstract class MyBaseString<Trait extends CharTraits, Allocator extends CharAllocator> {
private Trait traits_;
private Allocator allocator_;
private void initObjects() {
try {
ParameterizedType pt = (ParameterizedType) getClass().getGenericSuperclass();
String traitClassName
= pt.getActualTypeArguments()[0].toString().split("\\s")[1];
traits_ = (Trait) Class.forName(traitClassName).newInstance();
String allocatorClassName
= pt.getActualTypeArguments()[1].toString().split("\\s")[1];
allocator_ = (Allocator) Class.forName(allocatorClassName).newInstance();
} catch (Exception e) { throw new RuntimeException(e); }
}
public MyBaseString() { initObjects(); }
public void testObjects() {
System.out.printf("Trait compare 'a' and b %s\n", traits_.compare('a','b'));
System.out.printf("Trait allocate %s\n",
allocator_.allocate(10).getClass().getCanonicalName());
}
}
Strings
class MyString extends MyBaseString<DefaultCharTraits, DefaultAllocator> {}
public static void main(String[] args) {
final MyString ms = new MyString();
ms.testObjects();
}
Trait compare 'a' and b -1
Trait allocate char[]
Strings
В чем преимущество?
Strings
В чем преимущество?
Base String
Default String
ICString
UCString
Quoted String
Трейты:
- По-умолчанию
- Case Insensitive
- Upper Case
- Quoting
Strings
В чем преимущество?
Трейты:
- По-умолчанию
- Case Insensitive
- Upper Case
- Quoting
FastString
Default String
ICString
UCString
Quoted String
Аллокаторы
- По-умолчанию
- Быстрый
SlowString
SlowDefaultString
SlowICString
SlowUCString
SlowQuotedString
BaseString
Strings
В чем преимущество?
Трейты:
- По-умолчанию
- Case Insensitive
- Upper Case
- Quoting
DefaultCharTraits
Аллокаторы
- По-умолчанию
- Быстрый
CITraits
UCTraits
QTraits
DefaultAllocator
FastAllocator
FastDefaultString
DefaultString
UCString
FastUCString
Base
String
Strings
В чем преимущество?
Версия с композицией:
public class CompositionBaseString {
private CharTraits traits_;
private CharAllocator allocator_;
public CompositionBaseString(CharTraits traits,
CharAllocator allocator,
Object... args) {
traits_ = traits;
allocator_ = allocator;
}
public CompositionBaseString(Object... args) {
traits_ = new DefaultCharTraits();
allocator_ = new DefaultAllocator();
}
}
Strings
В чем преимущество?
Версия с композицией:
public class CompositionBaseString {
private CharTraits traits_;
private CharAllocator allocator_;
public CompositionBaseString(CharTraits traits,
CharAllocator allocator,
Object... args) {
traits_ = traits;
allocator_ = allocator;
}
public CompositionBaseString(Object... args) {
traits_ = new DefaultCharTraits();
allocator_ = new DefaultAllocator();
}
}
Ровно один аргумент по-умолчанию
Strings
В чем преимущество?
public class CompositionBaseString {
private CharTraits traits_;
private CharAllocator allocator_;
public CompositionBaseString(CharTraits traits,
CharAllocator allocator,
Object... args) {
traits_ = traits;
allocator_ = allocator;
}
public CompositionBaseString(Object... args) {
traits_ = new DefaultCharTraits();
allocator_ = new DefaultAllocator();
}
}
class MyString extends MyBaseString<DefaultCharTraits, DefaultAllocator> {}
class MyUCString extends MyUCString<UCCharTraits, DefaultAllocator> {}
class MyUCFString extends MyFastUCString<UCCharTraits, FastAllocator> {}
class MyICString extends MyICString<ICCharTraits, DefaultAllocator> {}
class MyICFString extends MyICFastString<ICCharTraits, FastAllocator> {}
Strings
В чем преимущество?
Инициализация через Spring, или аналогичное...
public class CompositionBaseString {
private CharTraits traits_;
private CharAllocator allocator_;
public void setTraits_(CharTraits traits_) {
this.traits_ = traits_;
}
public void setAllocator_(CharAllocator allocator_) {
this.allocator_ = allocator_;
}
}
JSON
JSON
json j = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{"answer", {
{"everything", 42}
}},
{"list", {1, 0, 2}},
{"object", {
{"currency", "USD"},
{"value", 42.99}
}}
};
j["object"] = { {"currency", "USD"},
{"value", 43.99} };
// a JSON value
json j_original = R"(
{
"baz": ["one", "two", "three"],
"foo": "bar"
}
)"_json;
// access members with a JSON pointer (RFC 6901)
j_original["/baz/1"_json_pointer];
// "two"
json::diff(j_result, j_original);
// [
// { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
// { "op": "remove","path": "/hello" },
// { "op": "add", "path": "/foo", "value": "bar" }
// ]
JSON
template <
template<typename U, typename V, typename... Args> class ObjectType = std::map,
template<typename U, typename... Args> class ArrayType = std::vector,
class StringType = std::string,
class BooleanType = bool,
class NumberIntegerType = std::int64_t,
class NumberUnsignedType = std::uint64_t,
class NumberFloatType = double,
template<typename U> class AllocatorType = std::allocator
>
class basic_json;
Спасибо!
this
Contacts:
-
Thinking In C++
Volume 2: Practical Programming - https://herbsutter.com/gotw/
Что почитать:
- Ник: Cadovvl
- Мыло: pavelandreevith@gmail.com
Алсо:
- Слава JavaNN!
- Слава лину
ксу!
Bonus
Curiously recurring template pattern
Bonus
Curiously recurring template pattern
class Base {
virtual void to_implement() = 0;
protected:
virtual ~Base() {}
public:
void f() {
to_implement();
}
};
class Derived : public Base {
void to_implement() {
cout << "Call to_implement" << endl;
}
};
Bonus
Curiously recurring template pattern
template<typename T>
class Base {
public:
void f() {
static_cast<T *>(this)->to_implement();
}
};
class Derived : public Base<Derived> {
public:
void to_implement() {
cout << "Call to_implement" << endl;
}
};
Bonus 2
Задача:
Форматирование телефона. В цифры вставляется не более двух тире чарез каждые две цифры с конца.
пример:
123 1-23
123456 12-34-56
12345678 1234-56-78
Bonus 2
#include <iostream>
#include <locale>
struct phone_formatter : std::numpunct<char> {
char do_thousands_sep() const override { return '-'; }
std::string do_grouping() const override { return std::string({2, 2, 0}); }
};
int main() {
std::locale loc(std::cout.getloc(), new phone_formatter);
std::cout.imbue(loc);
std::cout << 1234 << "\n";
std::cout << 1234567 << "\n";
std::cout << 123456789 << "\n";
std::cout << 12 << "\n";
return 0;
}
templates vs generics
By Cadovvl
templates vs generics
c++ templates compare to java generics
- 650