Та самая презентация

Докладчик: Я

Краткое введение в С++ для 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 >
using enable_if_t = typename enable_if<B,T>::type;

Пара слов о дизайне приложений

Пара слов о дизайне приложений

  • 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

Трейты:

  1. По-умолчанию
  2. Case Insensitive
  3. Upper Case
  4. Quoting

Strings

В чем преимущество?

Трейты:

  1. По-умолчанию
  2. Case Insensitive
  3. Upper Case
  4. Quoting

FastString

Default String

ICString

UCString

Quoted String

Аллокаторы

  1. По-умолчанию
  2. Быстрый

SlowString

SlowDefaultString

SlowICString

SlowUCString

SlowQuotedString

BaseString

Strings

В чем преимущество?

Трейты:

  1. По-умолчанию
  2. Case Insensitive
  3. Upper Case
  4. Quoting

DefaultCharTraits

Аллокаторы

  1. По-умолчанию
  2. Быстрый

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