На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
Страницы: (3) 1 [2] 3  все  ( Перейти к последнему сообщению )  
> Шаблоны — примеры применения и альтернативы на других языках
    Цитата Qraizer @
    Хм. Формально ничто не запрещает на функторах переписать... D_KEY, как думаешь, стоит ли?

    А зачем? :)

    Добавлено
    Цитата korvin @
    В Ocaml можно вот так сделать, но это только в теле функции, аналог try-with-resources в Java и прочих

    Да, с плюсами разница как раз в том, что только в функции это работает. В С++ же это так же будет работать и для полей и автоматически вызываться при разрушении объекта.
      Цитата korvin @
      void operator=(const CT_Sync&);

      Цитата korvin @
      void operator=(const Mutex_Sync&);

      А что, так можно перегружать?

      Обычно же пишут что-то в виде:

      ExpandedWrap disabled
        Type& operator=(const Type& t);
        Раст.
        ExpandedWrap disabled
          trait Policy {
              fn new() -> Self;
              fn lock(&mut self);
              fn unlock(&mut self);
          }
           
          struct LockGuard<'a, P: Policy> {
              p: &'a mut P,
          }
           
          impl<'a, P: Policy> LockGuard<'a, P> {
              fn new(p: &'a mut P) -> Self {
                  p.lock();
                  Self { p }
              }
          }
           
          impl<'a, P: Policy> Drop for LockGuard<'a, P> {
              fn drop(&mut self) {
                  self.p.unlock();
              }
          }
           
          struct Foo<P: Policy> {
              p: P,
          }
           
          impl<P: Policy> Foo<P> {
              fn new() -> Foo<P> {
                  Foo { p: Policy::new() }
              }
           
              fn do_smth(&mut self) {
                  let lock = LockGuard::new(&mut self.p);
                  // Do something
                  println!("Hello!");
              }
          }
           
          struct NoLock {}
           
          impl Policy for NoLock {
              fn new() -> Self {
                  Self {}
              }
           
              fn lock(&mut self) {}
              fn unlock(&mut self) {}
          }


        Добавлено
        Из удобного - спева написал версию с ручным lock-unlock, потом добавил LockGuard, заменил вызов lock на создание объекта LockGuard и компилятор сразу выдал ошибку - дескать, unlock руками вызывать не можешь, т.к. объект отдали. BC всё-таки удобная вещь :)
          Цитата D_KEY @
          Да, с плюсами разница как раз в том, что только в функции это работает. В С++ же это так же будет работать и для полей и автоматически вызываться при разрушении объекта.

          Спасибо, Кэп ))
            Можно так:

            ExpandedWrap disabled
              module Region :
                sig
                  type region
                  val ( #: )   : region -> ('a -> unit) -> 'a -> unit
                  val ( let& ) : (region -> 'a) -> ('a -> 'b) -> 'b
                end =
              struct
               
                type finalizer = unit -> unit
               
                type region = finalizer list ref
                
                let make () = ref []
                
                let ( #: ) r f v =
                  r := (fun () -> f v) :: !r
               
                let rec exit r =
                  match !r with
                  | []    -> ()
                  | f::fs ->
                    begin
                      f () ;
                      r := fs ;
                      exit r
                    end
                
                let ( let& ) : (region -> 'a) -> ('a -> 'b) -> 'b
                  = fun constr proc ->
                    let region = make () in
                    Fun.protect
                      ~finally:(fun () -> exit region)
                      begin fun () ->
                        let res = constr region in
                        proc res
                      end
               
              end
               
              open Region
               
               
              module File :
                sig
                  type t
                  val open_rw    : string -> region -> t
                  val read_line  : t -> string option
                  val write_line : t -> string -> unit
                end =
              struct
               
                type t =
                  {         path : string
                  ; mutable data : string list }
                
                let rec open_rw path region =
                  Printf.printf "++++ OPEN %s\n" path ;
                  let f = { path ; data = ["foo";"bar";"gee";"qux"] } in
                  region #: close f ;
                  f
                
                and close f =
                  f.data <- [] ;
                  Printf.printf "---- CLOSE %s\n" f.path
                
                let read_line f =
                  match f.data with
                  | [] ->
                    begin
                      Printf.printf "EOF\n" ;
                      None
                    end
                  | line::rest ->
                    begin
                      f.data <- rest ;
                      Printf.printf "READ %s FROM %s\n" line f.path ;
                      Some line
                    end
                
                let write_line f line =
                  Printf.printf "WRITE %s TO %s\n" line f.path ;
                  f.data <- List.append f.data [line]
               
              end
               
               
              module SQL_DB :
                sig
                  type t
                  val connect : string -> region -> t
                  val select  : t -> string list
                  val insert  : t -> string -> unit
                end =
              struct
               
                type t =
                  {         table : string
                  ; mutable rows  : string list }
                
                let rec connect table region =
                  Printf.printf "++++ CONNECT TO %s\n" table ;
                  let c = { table ; rows = ["foo";"bar"] } in
                  region #: disconnect c ;
                  c
                
                and disconnect conn =
                  conn.rows <- [] ;
                  Printf.printf "---- DISCONNECT FROM %s\n" conn.table
                
                let select conn =
                  Printf.printf "SELECT * FROM %s\n" conn.table ;
                  conn.rows
                
                let insert conn value =
                  Printf.printf "INSERT INTO %s VALUE \"%s\"\n" conn.table value ;
                  conn.rows <- value :: conn.rows
                
              end
                  
               
              module Transfer :
                sig
                  type t
                  val make     : db:string -> file:string -> region -> t
                  val upload   : t -> unit
                  val download : t -> unit
                end =
              struct
               
                type t =
                  { db : SQL_DB.t
                  ; fd : File.t }
               
                let make ~db:conn_str ~file:path region =
                  let db = SQL_DB.connect conn_str region in
                  let fd = File.open_rw path region in
                  { db : SQL_DB.t
                  ; fd : File.t }
                
                let upload { db ; fd } =
                  let rec loop () =
                    match File.read_line fd with
                    | None -> ()
                    | Some line ->
                      begin
                        SQL_DB.insert db line ;
                        loop ()
                      end
                  in loop ()
               
                let download { db ; fd } =
                  let lines = SQL_DB.select db in
                  List.iter (File.write_line fd) lines
               
              end
               
               
              let _ =
                ( let& users = Transfer.make ~db:"users" ~file:"/tmp/users" in
                  Transfer.upload   users ;
                  Transfer.download users );
                
                print_endline "--------------------------------" ;
               
                ( let& posts = Transfer.make ~db:"posts" ~file:"/tmp/posts" in
                  Transfer.download posts ;
                  Transfer.upload   posts );
                
                print_endline "--------------------------------" ;
               
                ( let& users = Transfer.make ~db:"users" ~file:"/tmp/users" in
                  let& posts = Transfer.make ~db:"posts" ~file:"/tmp/posts" in
                  Transfer.download users ;
                  Transfer.download posts )

            https://godbolt.org/z/eb8e44av5
            ExpandedWrap disabled
              ++++ CONNECT TO users
              ++++ OPEN /tmp/users
              READ foo FROM /tmp/users
              INSERT INTO users VALUE "foo"
              READ bar FROM /tmp/users
              INSERT INTO users VALUE "bar"
              READ gee FROM /tmp/users
              INSERT INTO users VALUE "gee"
              READ qux FROM /tmp/users
              INSERT INTO users VALUE "qux"
              EOF
              SELECT * FROM users
              WRITE qux TO /tmp/users
              WRITE gee TO /tmp/users
              WRITE bar TO /tmp/users
              WRITE foo TO /tmp/users
              WRITE foo TO /tmp/users
              WRITE bar TO /tmp/users
              ---- CLOSE /tmp/users
              ---- DISCONNECT FROM users
              --------------------------------
              ++++ CONNECT TO posts
              ++++ OPEN /tmp/posts
              SELECT * FROM posts
              WRITE foo TO /tmp/posts
              WRITE bar TO /tmp/posts
              READ foo FROM /tmp/posts
              INSERT INTO posts VALUE "foo"
              READ bar FROM /tmp/posts
              INSERT INTO posts VALUE "bar"
              READ gee FROM /tmp/posts
              INSERT INTO posts VALUE "gee"
              READ qux FROM /tmp/posts
              INSERT INTO posts VALUE "qux"
              READ foo FROM /tmp/posts
              INSERT INTO posts VALUE "foo"
              READ bar FROM /tmp/posts
              INSERT INTO posts VALUE "bar"
              EOF
              ---- CLOSE /tmp/posts
              ---- DISCONNECT FROM posts
              --------------------------------
              ++++ CONNECT TO users
              ++++ OPEN /tmp/users
              ++++ CONNECT TO posts
              ++++ OPEN /tmp/posts
              SELECT * FROM users
              WRITE foo TO /tmp/users
              WRITE bar TO /tmp/users
              SELECT * FROM posts
              WRITE foo TO /tmp/posts
              WRITE bar TO /tmp/posts
              ---- CLOSE /tmp/posts
              ---- DISCONNECT FROM posts
              ---- CLOSE /tmp/users
              ---- DISCONNECT FROM users
              Цитата OpenGL @
              ExpandedWrap disabled
                struct Foo<P: Policy> {
                    p: P,
                }

              В оригинальном примере в Foo не было поля p =/
              С полем-то каждый может :D
              Сообщение отредактировано: korvin -
                Цитата korvin @

                В оригинальном примере в Foo не было поля p =/

                Это да. Но с другой стороны - чем оно мешает? На sizeof класса это не влияет, так что аналог empty base optimization (или как оно там в плюсах зовётся) тут применяется
                  Цитата Majestio @
                  Цитата korvin @
                  void operator=(const CT_Sync&);

                  Цитата korvin @
                  void operator=(const Mutex_Sync&);

                  А что, так можно перегружать?

                  Обычно же пишут что-то в виде:

                  ExpandedWrap disabled
                    Type& operator=(const Type& t);

                  Это не обычная перегрузка. Это перегрузка с целью запрета генерировать эти спец.методы компилятором. Цель в том, чтобы запретить копирования и присваивания. Если их просто никак не объявить, компилятор способен будет сгенерировать их сам, если же они объявлены, то генерировать он уже ничего не будет. Но т.к. я их не определил, то при попытке скопировать или присвоить будет ошибка линковки. Т.е. цель запрета на эти операции достигнута, пусть и несколько странным способом. Т.к. я не планирую их использовать, то и прототип может быть любым, Стандарт не запрещает возвращать что ни попадя. Конечно, для обычной перегрузки так писать не стоит, кроме очень специфичных случаев.
                  В новых Стандартах для такого запрета есть более правильные методы, но на момент написания того кода их ещё не было, или поддерживающие новые фишки Стандарта компиляторы мне не были доступны.
                    Цитата Qraizer @
                    Это не обычная перегрузка. Это перегрузка с целью запрета генерировать эти спец.методы компилятором. Цель в том, чтобы запретить копирования и присваивания. Если их просто никак не объявить, компилятор способен будет сгенерировать их сам, если же они объявлены, то генерировать он уже ничего не будет. Но т.к. я их не определил, то при попытке скопировать или присвоить будет ошибка линковки. Т.е. цель запрета на эти операции достигнута, путь и несколько странным способом. Т.к. я не планирую их использовать, то и прототип может быть любым, Стандарт не запрещает возвращать что ни попадя. Конечно, для обычной перегрузки так писать не стоит, кроме очень специфичных случаев.
                    В новых Стандартах для такого запрета есть более правильные методы, но на момент написания того кода их ещё не было, или поддерживающие новые фишки Стандарта компиляторы мне не были доступны.

                    :good:

                    Что-то типа X& operator=(const X&) = delete; ?
                      Угу. ;)
                        Цитата D_KEY @
                        Тут вся фишка в С++ в том, что политиками ты статически как бы "собираешь" свой тип, но при этом ты ничем не жертвуешь в динамкие. Т.е. как будто ты сам писал все эти классы руками делал.
                        Т.е. абстракция остается исключительно в коде, а не в итоговой программе. Не думаю, что в других языках такое есть.


                        В C# варианте, если IPolicy будут реализовывать структуры, а не классы, как в примере, то в ран тайм тоже не будет накладных расходов.
                          Привет)
                          Справедливости ради, пример на C# был написан так, чтобы внешне быть похожим на плюсовый. На самом деле практической ценности в нём нет, так писать не стоит, дженерики тут не нужны. Достаточно передать в конструктор класса Foo нужный экземпляр ISync.
                          И да, что-то "собрать" при компиляции можно с помощью кодогенерации (Roslyn, annotation processing, KSP и т.д), но тут это из пушки по воробьям)
                            Цитата IL_Agent @
                            Достаточно передать в конструктор класса Foo нужный экземпляр ISync.


                            Вот как раз в этом случае у тебя будут потери на косвенный вызов метода через интерфейсную ссылку. Если это не парит, то и прекрасно. А во в случаях когда каждая микросекунда важна - дженерики - наше всё (в .NET)
                              Цитата jack128 @
                              Вот как раз в этом случае у тебя будут потери на косвенный вызов метода через интерфейсную ссылку.

                              Хочешь сказать, что вызов метода конкретного класса быстрее, чем вызов того же метода, но через интерфейс? Есть пруфы?
                                Для вызова метода интерфейса ж нужно сначала извлечь адрес метода из VMT и только потом сделать call, но тут разница микроскопическая. А вот что реально важно, так это inline. Если у нас в коде есть только интерфейс, то компилятор(JIT в случае .NET) не в курсе, что именно за метод должен вызваться и честно делает call <адрес метода> , вот если у нас есть структура мы вызваем myStruct.MyMethod(args) то jit сможет заинлайнить MyMethod со всеми вытекающими.

                                В .NET классический пример всего этого - это generic math в .NET 6 и ниже. Только после .NET7 таких примеров хрен нагуглишь :-D . А самому писать лень, сорри.
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) 1 [2] 3  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0645 ]   [ 14 queries used ]   [ Generated: 16.06.25, 13:30 GMT ]