Ответы пользователя по тегу C++
  • Почему lower_bound не видит operator, хотя он определен?

    operator< ищется через ADL. Нельзя определить оператор для чужих типов, и чтобы его подхватили алгоритмы. Предлагаю такое решение: вместо char искать свою структуру (её можно определить просто как struct с char), для которой определить сравнение так же, как ты это сделал с char.
    Ответ написан
    5 комментариев
  • Как выбрать тип в runtime?

    std::any позволяет сохранить в себя объект любого типа, после чего через any_cast вытащить значение, если оно такого типа, как мы предполагаем. Проверка осуществляется через RTTI. Если поддерживается много конкретных типов, вы должны писать здоровенную цепочку if-else-if. В таком случае лучше уж идти через наследование.
    Ответ написан
    Комментировать
  • Есть ли область видимости у директив препроцессора C++?

    Нет, директивы препроцессора не ограничены никакими областями видимости. Они заменяют абсолютно все вхождения соответствующего имени после своего определения. Пример:

    namespace what {
    #define apples 2
    }
    
    namespace stuff {
        class foo {
        private:
            int apples = 3;  // ОШИБКА: 2 - недопустимое имя
        public:
            int read_apples() {
                return apples;  // 2
            }
        };
    }


    Мораль: не используйте макросы там, где можно обойтись constexpr константами или inline функциями. А там, где они необходимы, давайте им длинные страшные КРИЧАЩИЕ_ИМЕНА.
    Ответ написан
    Комментировать
  • Как спарсить строку с выбором вариантов на C++ Builder?

    Общий подход предлагаю такой. Заводите std::vector<std::vector<std::string>>. Каждый внутренний вектор хранит варианты выбора для очередного куска строки. В частности, для кусков строки между вариативными частями будем считать, что есть всего 1 вариант выбора. Соответственно, весь вектор векторов — это последовательность таких вариативных частей. Задача делится на 2 части:

    1. Парсинг входной строки в нашу структуру. Парсим в цикле, вытаскивая из исходной строки по 1 символу, и аккумулируем в промежуточное состояние. Нам понадобится std::string для текущего варианта и std::vector<std::string> для текущей вариативной части.

    2. Самое простое, когда наш вектор векторов заполнен, создаём пустой std::string, и накидываем туда из каждого внутреннего вектора по 1 варианту.
    Ответ написан
    Комментировать
  • Что делает этот конструктор?

    Это объявление (declaration) конструктора. Значения полей должны быть заданы в определении (definition). Раз определения тут нет, значит, его нужно искать где-то в другом месте. Возможно, вы найдёте его в одном из следующих шагов. Возможно, его написание оставлено как упражнение для читателя. Возможно, содержимое конструктора (присвоение параметров полям) авторы посчитали очевидным.

    Пример определения, которое должно следовать за таким классом:
    Cls::Cls(char c, double d, int i)
        : c(c), d(d), i(i) {}
    Ответ написан
    Комментировать
  • Как найти часто встречающиеся тексте последовательности?

    Обратите внимание, что std::string использует SBO, то есть не выделяет доп. память в куче для коротких строк. Ещё стандартные мапы в C++ крайне неэффективны, подключите библиотеку. Идея такова:
    1. Хешмап "строки -> счётчики" для строк длины 3
    2. Хешмап "строки -> счётчики" для строк длины 4, но добавляем туда только строки, у которых начало длины 3 входит в мапу из (1) не менее 2 раз
    3. Хешмап "строки -> счётчики" для строк длины 5, но добавляем туда только строки, у которых начало длины 4 входит в мапу из (2) не менее 2 раз
    Ответ написан
    Комментировать
  • Как правильно использовать typedef?

    Убери предпоследнюю строку. Компилятор жалуется на дублирующееся объявление метода IdentifyLength, а не на typedef. К слову, в новом коде вместо typedef следует использовать using:

    using DigitArea = unsigned int;

    А ещё лучше - использовать типы из <cstdint> по умолчанию. Например:

    using DigitArea = std::int64_t;
    Ответ написан
    Комментировать
  • Почему компилируется 'Hello, World!', хотя был введен другой код?

    #include "std_lib_facilities.h"
    Вы уверены, что скопировали в проект файл std_lib_facilities.h и подключили его должным образом?
    Ответ написан
    1 комментарий
  • Как собрать рабочее окружение для IPad для программирования на С++?

    Всё программы, позволяющие компилировать код на мобильных устройствах, особенно на iPad, на самом деле шлют код на компиляцию в один из популярных сервисов. Они позволяют компилировать только игрушечные, учебные программы, и не годятся для много-мегабайтных и гигабайтных сборок.

    Чтобы программировать через iPad в пути, рекомендую TeamViewer или аналоги. Конечно, здесь важно стабильное, скоростное подключение к интернету.
    Ответ написан
    Комментировать
  • Есть ли в для C++14 map с поддержкой constexpr хэша?

    Предрасчитанный ключ - вполне валидная стратегия, если расчёт хеша сильнее влияет на производительность, чем хранение дополнительных 8 байтов на элемент.

    template <typename T>
    class hashed {
        T value_;
        size_t hash_;
    
        friend class std::hash<hashed<T>>;
    public:
        template <typename... Args>
        constexpr hashed(Args&&... args) :
            value_(std::forward<Args>(args)...),
            hash_(std::hash<T>()(value_))
        {}
    
        // rule of zero
    
        constexpr T& get() & noexcept { return value_; }
        constexpr const T& get() const& noexcept { return value_; }
        constexpr T&& get() && noexcept { return value_; }
        constexpr const T&& get() const&& noexcept { return value_; }
    };
    
    namespace std {
        template <typename T>
        struct hash<hashed<T>> {
            constexpr size_t operator()(const hashed<T>& x) const noexcept {
                return x.hash_;
            }
        };
    }
    
    std::unordered_map<hashed<std::string>, int> cache;
    auto it = cache.find("property1");  // хеш на этапе выполнения
    
    // хеш на этапе компиляции, работает с constexpr std::string из C++20
    constexpr auto h = hashed<std::string>("property1");
    
    auto it2 = cache.find(h);  // предрасчитанный хеш
    Ответ написан
  • Для какой задачи на практике может потребоваться использовать в качестве параметра шаблона указатель на функцию-член?

    Когда лень писать лямбду. Часто [](widget& w) { return w.foo(); } можно заменить на widget::foo.
    Ответ написан
    Комментировать
  • Как при открытии файла имя файла указывать переменной?

    Замечу, что в современном C++, c_str не нужно:

    auto fullPath = filename + format;
    std::ofstream file(fullPath);

    Если у вас требуется c_str, то вы используете C++98, добавьте флаг -std=c++14.
    Ответ написан
    Комментировать
  • В чем заключается выбор между C и С++ для написания драйверов?

    C++ не может повредить. Если вы используете virtual, RTTI, exceptions, iostreams, то вы платите за них, но если эта цена неприемлема - просто не используете их.

    Однако C++, особенно C++11 и C++14, часто не поддерживаются компилятором, когда приходится собираться не под уютные gcc/clang x86, а что-нибудь специфическое, вроде Arduino или CUDA. Ещё в ядре Linux C++ традиционно под запретом.

    Так что посмотрите, можете ли вы использовать C++ в вашем конкретном случае. Если нет, то выбирать не из чего.
    Ответ написан
    Комментировать
  • Как изменить значение поля enum в рантайме?

    Вам нужны tagged union. Вот как это выглядело бы на Swift, например:

    enum Foo {
        case qqq(Int)
        case www(Int)
    }
    
    let x = Foo.qqq(5)
    let y = Foo.www(10)


    На C++ это часто эмулируется с помощью наследования:

    class Foo {
    public:
        virtual ~Foo() = 0;
    };
    
    class qqq : public Foo {
    public:
        int value;
        explicit qqq(int value);
    };
    
    class www : public Foo {
    public:
        int value;
        explicit www(int value);
    };
    
    using FooPtr = std::unique_ptr<Foo>;
    FooPtr makeQqq(int value);
    FooPtr makeWww(int value);
    
    FooPtr x = makeQqq(5);
    FooPtr y = makeWww(10);


    Я опустил небольшое количество кода, который, я не сомневаюсь, вы могли бы сами закончить, если действительно хотите заставить этого монстра работать :)

    Есть и более чистый способ: подключите либу type_safe (кликабельно).

    #include <type_safe/strong_typedef.hpp>
    #include <type_safe/variant.hpp>
    
    namespace ts = type_safe;
    
    using qqq = ts::strong_typedef<int>;
    using www = ts::strong_typedef<int>;
    using Foo = ts::variant<qqq, www>;
    
    // ...
    
    auto x = Foo(qqq(5));
    auto y = Foo(www(10));
    
    if (x.has_value(ts::variant_type<qqq>{})) {
        qqq value = x.value(ts::variant_type<qqq>{}));
        std::cout << "qqq" << ' ' << static_cast<int>(value);
    }
    Ответ написан
    Комментировать
  • Как вывести на экран все содержимое массива?

    При помощи этой либы:
    fmt::print("Total: [{}]\n", fmt::join(total_1.begin(), total_1.end(), ", "));
    //=> Total: [1, 2, 3]
    Может, кто-то ещё переметнётся на сторону printf-стиля :]
    Ответ написан
  • Почему функция rand() возвращает одно и то же значение?

    Раз уж у вас C++, то от использования rand() вообще лучше отказаться и пользоваться более точной C++-ной либой <random>:

    // Важно: создание этого объекта занимает некоторое время,
    // его лучше использовать для генерации всех случайный чисел
    std::default_random_engine engine(std::random_device()());
    
    // Легковесный объект-диапазон для генерации целых чисел
    // В std есть и куча других полезных распределений
    std::uniform_int_distribution<int> distribution(min,max);
    
    for (int i = 0; i < N; ++i) {
        int random_number = distrubution(engine);
        std::cout << random_number << std::endl;
    }
    Ответ написан
    Комментировать
  • Как сделать std::list размером в 12 байтов?

    1. Скопировать std::list из хедеров VS2003 в свой хедер my_list.h
    2. Переименовать этот std::list в класс (не std) my_list
    3. Использовать my_list вместо std::list при работе с библиотекой
    4. Если там в хедерах прописан std::list&, то при вызове функции можно передавать reinterpret_cast<std::list&>(my_list_instance), чтобы пропихнуть тот список,
      который нужен либе
    Ответ написан
    Комментировать
  • Почему выдает ошибку-неоднозначный вызов перегруженной функции?

    1. Вместо #include <math.h>, в C++ нужно использовать #include <cmath>. Она более производительна в некоторых случаях, и там есть больше функций для C++.
    2. Зачем вводить int, если всё равно вычисляем double? Тогда программа не сойдёт с ума при больших координатах.
    3. Вместо x*x можно использовать pow(x,2) без потери производительности.

    Итого:
    #include <iostream>
    #include <cmath>
    #include <iomanip>
    using namespace std;
    
    int main()
    {
        double x1, x2, y1, y2;
        cin >> x1 >> x2 >> y1 >> y2;
        cout << fixed << setprecision(2) << sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
        return 0;
    }
    Ответ написан
    Комментировать