Ответ
Нет, это крайне не рекомендуется для std::map, std::set, std::unordered_map и std::unordered_set.
Причины:
- Проблемы точности: Из-за двоичного представления чисел с плавающей точкой операции могут давать разные результаты на разных архитектурах или с разными уровнями оптимизации. Значение, вычисленное как
0.1 + 0.2, не будет бинарно равно литералу0.3. - Ненадёжное сравнение:
std::mapиспользуетoperator<для упорядочения. Дляfloatэто приводит к недетерминированному поведению из-за погрешностей. - Неподходящее хеширование:
std::unordered_mapтребует строгого равенства ключей. Два математически равныхfloatмогут иметь разные битовые представления и, следовательно, разные хеши.
Альтернативы, которые я использовал:
- Фиксированная точка: Умножить на коэффициент и использовать целочисленный тип.
std::map<int, std::string> priceMap; // Цена в рублях с копейками float price = 123.45f; priceMap[static_cast<int>(price * 100)] = "Товар"; // Ключ: 12345 - Кастомный компаратор с эпсилон-окрестностью (осторожно, нарушает строгое слабое упорядочение):
struct FloatCompare { bool operator()(float a, float b) const { const float eps = 1e-6f; if (std::abs(a - b) < eps) return false; // Считаем равными return a < b; } }; // std::map<float, Value, FloatCompare> map; // Рискованно - Использовать
std::ratioили библиотеки decimal для финансовых расчётов.
В production-коде я всегда избегаю float/double как ключей, предпочитая целочисленные или строковые представления.