Перейти к содержанию
    

juvf

Свой
  • Постов

    1 610
  • Зарегистрирован

  • Посещение

  • Победитель дней

    2

Сообщения, опубликованные juvf


  1. В 26.06.2024 в 16:52, Arlleex сказал:
    Communication() { name = const_cast<char*>("Communication"); }

    вангую, что name, это  char* Module::name; Иначе, зачем бы приводить const char* к char*? Тут уже проблема. 

    В 26.06.2024 в 17:53, Forger сказал:

    такая запись мне кажется менее перегруженной "значками" ))  Исключительно, вкусовщина )

     Communication() { setName("Communication"); }

    такая запись во 1-х protected использует, во 2-х в внутри steName всё тоже const char* к char* приводиться. А не лучше  бы ли делать const char* Module::name? 

    Communication() : Module("Communication") {}; - ещё менее перегруженная запись, чем c setName(), не требует protected, не нужно на константную строку ссылаться через неконстантный указатель.

  2. В 26.06.2024 в 12:04, Forger сказал:

    это как раз явное, т.к. жестко прописано в стандарте со времен царя гороха )

    это называется "неявное". Со времён царя гороха в стандарте с++ говорится, что по умолчанию будет приват. "по умолчанию" - читай "при неявном" ("по умолчанию" - значит когда "нет явного указания"). Более того, в с++14

    Цитата

    Members of a class defined with the `class` key have private access by default; members of a class defined with the `struct` key have public access by default. Access specifiers can be provided explicitly.

     

  3. В 26.06.2024 в 10:25, Arlleex сказал:

    В чем недостатки такой записи?

    я не вижу недостатков. я вижу финальный класс, у которого ЕСТЬ приватный конструктор. Т.е. объект этого класса всё таки можно создать (самим классом).  Если объявить класс как  final privat и удалить конструктор

    class MyClass final {
      public:
        ...
      
      private:
        MyClass() = delete;
    };

     тут я вижу: 1) от этого класса нельзя наследосаться. 2) нельзя создать объект этого класса. Т.е. не то что пользователь не сможет  сделать MyClass obj;, но и не существует ни каких методов в этом классе, чтобы создать объект этого класса, т.е. нет ни каких статический функций (как в синглтоне), аля MyClass *MyClass::create(){return new MyClass); нет.  

  4. если класс объявлен как final public и удалить конструктор по умолчанию и явно не определить конструкторы копирования и перемещения, компилятор создаст их автоматически в public. Чтобы гарантированно нельзя было создать объект класса - удалите эти конструкторы.

    class A final 
    { 
    public:	
    	A() = delete; // Удаляем конструктор по умолчанию
    
    	A(const A&) = delete;
    	A(A&&) = delete;
    	A& operator=(const A&) = delete;
    	A& operator=(A&&) = delete;
    
    private: 
    	int a; 
    }

    лучше объявить класс как final private, тогда все неявные конструкторы по умолчанию будут также private

  5. В 24.06.2024 в 19:32, EdgeAligned сказал:

    Даже вот этот, который разбирали прямо сейчас - вынести любые методы можно в .cpp, но если этот же метод сделан шаблонным - уже нельзя.

    и в чем тут косяк? это не баг, это фича.

  6. В 24.06.2024 в 17:40, razrab83 сказал:

    А зачем тут нужна явной специализация? почему не сделать вместо явной специализации просто функцию не заморачиваясь шаблонами?

    в отдельном взято случае, возможно просто функция без шаблона лучше/быстрее/понятнее/читаемо.... но, вы написали шаблон 

    template <typename T> void f(T value) { // Общая реализация для всех типов }

    потом его используете (и не толко вы, а все пользователи вашего кода

    f<int>(a);

    f<uint>(b);

    есть некое API, и тут вас торкнуло для uint сделать немного по другому. Можно убрать шаблон для uint и сделать отдельную функци, тогда вы измените API и код, который уже написан и использует f<uint>(b); не будет собираться.

  7. В 24.06.2024 в 17:27, Forger сказал:

    поскольку в целях безопасности все поля класса должны быть исключительно private (реже protected), то доступ к ним должен быть возможен только через соотв методы этого класса

    по мойму тут путаница тёплого с мягким. Задача про которую говорит  jcxz - обработать много данных класса за раз (когда нужно однотипно обработать несколько членов класса). При чем тут приват? У вас есть класс с членами приватными (или протект, или паблик - не важно) A1, A2, A3, ... ,An. У этого класса есть паблик метод calcData(). Вызываем этот метод и нужно в нем обработать однотипно свои приватные члены класса. 

  8. В 23.06.2024 в 20:31, Arlleex сказал:

    Я хотел, чтобы в заголовочнике был только "интерфейс" для быстрого охвата глазами. А в реализации уже потроха - туда смотреть не надо.

    это не единственная причина убрать шаблон в cpp и сделать явную инстанцировку. Если реализовать шаблон полностью в *.h. (или в *.h и в *_impl.h), допустим потом если вызвать эту функцию f<int> 10 раз в одном файле, то компилятор встретив первый раз f<int>, сгенерирует код и после ужё встретив в этом файле f<int> компиялтор будет использовать уже сгенерированные код. 

    Но если вы ещё в десяти файлах исходников вызовите f<int>, то компилятор будет гернерить код f<int> для каждого вашего *.cpp, где вы его вызовите.  Один раз на каждый *.cpp где хоть раз есть вызов  f<int>. Т.е. ваш main.o будет содержать отдельную f<int>, ваш noMain.o будет содержать отдельную f<int>, и все остальные объектники будет каждый содержать свой f<int>. Потом, при  линковке, линкер выкинет все дубликаты и будет всего одна f<int> для всех. 

     

    Если вы вынесете определение шаблона f<int> в *.cpp и сделаете явную  инстанцировку, то при компиляции myTemplate.cpp и встетив строчку template void f<int>(int); у вас компиялтор сгенерирует f<int> в отдельный myTemplate.o . При компиляции остальных файлов *.срр генерации f<int> не будет. Получите  myTemplate.0 с кодом  f<int>. Линковщик потом свяжет  весь проект. 

    Итоговый код будет одинаковый в обоих случаях, но время компиляции уменьшится. У каждого метода есть ++ и --.

  9. В 24.06.2024 в 13:54, Arlleex сказал:

    Т.е. мы говорим компилятору - у нас где-то есть template. А ну-ка создай прототип шаблонной функции с таким-то типом. Так?

    да. компилятор создаст вам функцию 

    void f(int value)
    {
    // Общая реализация 
    }
    В 02.06.2024 в 19:24, Arlleex сказал:

    В общем купил себе книжечку, толстееееннную))

     

    а в этой книжке это не изложено? Или там нужно выкуривать эту инфу? 

    ps так то конечно, лучше сразу получить знания на практике: есть практическая цель - есть вопрос: "а как это решить и в чем различие?". Чем курить книжку долгое время без практики. Все равно половину забудешь.  Просто интересно, там это есть или нет?

  10. В 24.06.2024 в 13:15, Arlleex сказал:

    Имеет ли это какое-то значение? Или это на уровне синтаксиса абсолютно ничего не значит?

    имеет. тут стрельнуть себе в ногу можно... 

    template<> func<int>(int a) { } //это явная специализация
    template func<int>(int a); // это явная инстанцировка

    в чем различие!? Когда нужно сделать отдельную реализацию для белой вороны какого-то типа, то делается явная специализация. поясню на примере

    Файл myTemplate.cpp

    #include "myTemplate.h"
    
    template <typename T> void f(T value)
    {
    // Общая реализация для всех типов
    }
    
    // Реализация явной специализации для типа `unsigned int`
    template <>
    void f<unsigned int>(unsigned int value) 
    {
        printf("Hello unsigned int = %u");
    }
    
    
    // Явная инстанцировка для нужных типов
    template void f<int>(int);
    template void f<double>(double);

    Использование

     

    #include "myTemplate.h"
      
    int main()
    {
    int a = -1;
    double b = 3.14;
    unsigned int c = 123;
    
    f<int>(a); // Использует общую реализацию
    
    f<double>(b); //Использует общую реализацию
      
    f<unsigned int>(c); //Использует специализированную реализацию, которая выводит "Hello unsigned int = *"
      
    return 0;
    }

    вобщем как-то так... 

     

    • Upvote 1
  11. В 23.06.2024 в 20:31, Arlleex сказал:

    Я хотел, чтобы в заголовочнике был только "интерфейс" для быстрого охвата глазами. А в реализации уже потроха - туда смотреть не надо.

    I. Стандартный подход

    отделить мух от котлет через имплементарный заголовок с реализацией

    в файле myTemplate.h

    template <typename T>
    void f(T value);
    
    #include "myTemplateImpl.h" // Включаем реализацию здесь 

    Файл myTemplateImpl.h

    template <typename T>
    void f(T value)
    {
    // Реализация функции
    } 

    В этом случае мы отделяем объявление и определение шаблонной функции в разные файлы, но включаем файл с реализацией myTemplateImpl в конце файла с объявлением myTemplate.h.

     

    II. альтернативный подход

    Сделать инстанцировку в исходном файле.

    Файл myTemplate.h

    template <typename T>
    void f(T value); 

    Файл myTemplate.cpp

    #include "myTemplate.h"
    
    template <typename T>
    void f(T value)
    {
    // Реализация функции
    }
    
    // Явная инстанцировка для нужных типов
    template void f<int>(int);
    template void f<double>(double);

    Использование

    #include "myTemplate.h"
      
    int main() 
    {
        float a = 1.0f;
        double b = 3.14;
        f<float>(a); //для варианта II ошибка, т.к. нЭт его (нет инстанцировки для float в cpp)
        f<double>(b); //будет работать для обоих вариантов
        return 0;
    }

     

    • Upvote 2
  12. вроде как в C++ нет прямого способа передать список инициализации {1, 2} в функцию,  без std::initializer_list (может ошыбаюсь). Можно использовать перегрузку шаблонной функции или макрос создающий массив

    template<int N> 
      void f1(int (&arr)[N]) 
    { 
      for (int i = 0; i < N; ++i) 
      { 
        printf("%d ", arr[i]);
      } 
      std::cout << std::endl; 
    } 
    // Вспомогательная функция
    template<int... Args> 
      void f2(Args... args) 
    {  
      int arr[] = { args... }; 
      func(arr); 
    } 
    
    int main() 
    { 
    
      f2(1, 2);   // вызов f2 развернется в вызов f1 с массивом из двух элементов 
      f2(3, 4, 5); // вызов f2 развернется в вызов f1 с массивом из трех элементов 
      
      //можно без прокладки f2, но кто-то должен создать массив, например макрос
      #define F3(...) { int temp[] = { __VA_ARGS__ }; f1(temp); }
      
      F3(1, 2);
      F3(3, 4, 5);
      return 0; 
    }

     

    • Upvote 2
  13. В 03.06.2024 в 13:23, Arlleex сказал:

    это фишка компилятора C++, а не библиотек

    да самому стало интересно.... 

    // Online IDE - Code Editor, Compiler, Interpreter
    
    #include<stdio.h>
    #include <iostream>
    
    template<typename... Args> 
      void send(int firstByte, Args... args) 
    {
      auto print = [](auto& arg) { std::cout << arg << " "; };//лямда, дла печати каждого аргумента
      
       std::cout << (firstByte == 0 ? "code0()" : "code1()") << std::endl;
    
      (print(args), ...);
       std::cout << std::endl;
       
    }
    // Обертка для sendCommand 
    template<typename... Args> 
     void sendCommand(Args... args) 
    { 
    	send(0, args...); 
    } 
    
    // Обертка для sendData 
    template<typename... Args> 
    void sendData(Args... args) 
    { 
    	send(1, args...); 
    }
    
    int main() {
        // Примеры использования
        std::cout << "sendCommand(0x12) -> ";
        sendCommand(0x12);             // вызовется send(0, 0x12)
        
        std::cout << "sendCommand(0x12, 0x34) -> ";
        sendCommand(0x12, 0x34);       // вызовется send(0, 0x12, 0x34)
        
        std::cout << "sendCommand(0x12, 0x34, 0x56) -> ";
        sendCommand(0x12, 0x34, 0x56); // вызовется send(0, 0x12, 0x34, 0x56)
    
        std::cout << "sendData(0x12, 0x34) -> ";
        sendData(0x12, 0x34);          // вызовется send(1, 0x12, 0x34)
    
        // Примеры с массивами и строками
        std::cout << "sendCommand(\"hello\") -> ";
        sendCommand("hello");          // вызовется send(0, "hello")
    
    
        unsigned char buf[3] = {0x01, 0x02, 0x03};
        std::cout << "sendData(buf) -> ";
        sendData(buf);                 // вызовется send(1, buf)
    
        return 0;
    }

    Проверил тут на с++17. выхлоп

    Цитата

    sendCommand(0x12) -> code0()
    18 
    sendCommand(0x12, 0x34) -> code0()
    18 52 
    sendCommand(0x12, 0x34, 0x56) -> code0()
    18 52 86 
    sendData(0x12, 0x34) -> code1()
    18 52 
    sendCommand("hello")) -> code0()
    hello 
    sendData(buf) -> code1()

     

    • Thanks 1
  14. В 31.05.2024 в 19:41, Arlleex сказал:

    Т.е. можно ли обойтись без обращения к std вовсе?

    В 31.05.2024 в 22:15, Arlleex сказал:

    Было бы здорово, если можно было бы перегрузить реализации send() под 2 варианта: аргумент-массив, и аргумент-список (параметры через запятую).

    если без std, то не получится определить переменное кол-во аргументов. для поддержки разного числа аргументов, нужен перегруз функции sendCommand и sendData для одного, двух и трех аргументов. Если нужно больше аргументов, то добавить соответствующие перегрузки. 

  15. // Основная шаблонная функция 
    send template<typename... Args> 
      void send(int dataCommand, Args&&... args) 
    { 
      if (dataCommand == 0) 
      { 
        std::cout << "sendCommand called with arguments: "; 
      } 
      else 
      { 
        std::cout << "sendData called with arguments: "; 
      } 
      (std::cout << ... << args) << std::endl; 
    } 
    // Обертка для sendCommand 
    template<typename... Args> 
    void sendCommand(Args&&... args) 
    { 
      send(0, std::forward<Args>(args)...); 
    } 
    // Обертка для sendData 
    template<typename... Args> 
      void sendData(Args&&... args) 
    { 
      send(1, std::forward<Args>(args)...); 
    } 

     

    int main() 
    { 
      // Примеры использования 
      sendCommand(0x12); // вызовется send(0, 0x12) 
      sendCommand(0x12, 0x34); // вызовется send(0, 0x12, 0x34) 
      sendCommand(0x12, 0x34, 0x56); // вызовется send(0, 0x12, 0x34, 0x56) 
      sendData(0x12, 0x34); // вызовется send(1, 0x12, 0x34) 
      
      // Примеры с массивами и строками 
      sendCommand("hello"); // вызовется send(0, "hello") 
      unsigned char buf[3] = {0x01, 0x02, 0x03}; 
      sendData(buf); // вызовется send(1, buf) 
      return 0; 
    }

     

    • Thanks 1
  16. В 25.05.2024 в 21:40, Mty сказал:

    А можете рассказать что такое месаджбоксы, слоты/сигналы ?

    гугл забанил?

    В 25.05.2024 в 21:40, Mty сказал:

    Я что то не встречал подобного во FreeRTOS.

    мой ответ касается вообще любой ОС (да и в вопросе про фрииртос ни слова), мой прием также применим и в FreeRTOS. Или вы думаете что в Linux можно использовать я использую  общие данные, а во FreeRTOS нет?

    Вам ни кто не мешает реализовать свои  флаги, эвенты, месаджбоксы, слоты/сигналы в любой ОС.

  17. В 19.05.2024 в 18:00, Arlleex сказал:

    Ну да, с перегрузкой действительно можно написать примерно то же, что делает борланд)

    Ну вот, дожили. Теперь используем всякие финты/костыли/растяжки в пуре с++, чтобы его приблизить к борланду. фэйспалм.

  18. У меня такой прием - Не использую общих данных. Не то что, для нескольких потоков, даже для одного потока. Не должны разные таски использовать общие данные. Каждая задача занимается своим делом и своими данными и нефиг ей лезть в чужие данные. Для передачи сообщений в др. таски использую механизмы ОС (флаги, эвенты, месаджбоксы, слоты/сигналы).  

  19. В 19.04.2024 в 11:01, alm сказал:

    Странно. Возможно, от моего провайдера зависит.

    VPN на компах включен? Без vpn даже ручками не обновиться, не скачать.

    В 19.04.2024 в 11:01, alm сказал:

    Приведенную выше фразу -

    а какое отношение эта фраза имеет к кубу? какой-то пакистанский инженер, что-то там ляпнул... 

×
×
  • Создать...