Единицы измерения в C++
я работаю над игровым движком, и в настоящее время я застрял в разработке системы ввода-вывода. Я сделал это так, что сам двигатель не справляется любой форматы файлов, но скорее позволяет пользователю реализовать все, что он хочет, создав *.dll
файл с appriopriatly названными функциями внутри. Хотя это само по себе не было большой проблемой, моя главная забота-последствия, которые, вероятно, будут видны во время использования двигателя.
я создал простой resource
интерфейс как базовый класс для всех вещей, которые пользователь может придумать, и я пытаюсь расширить его, сделав простые дочерние классы, посвященные общим типам данных, поэтому пользователю не нужно реализовывать основы самостоятельно (в настоящее время я думаю о audio
, image
, data
и mesh
). Начиная с audio
класс, я суммировал своеобразную проблему, пытаясь решить, в каком типе я должен хранить информацию о частота. Обычный блок Герц, поэтому я решил сделать это unsigned int
.
однако здесь есть небольшая проблема-что делать, если пользователь попытается установить его в килогерц? Предположим, что какой-то абстрактный формат файла может хранить его в обеих единицах на мгновение. Я сделал простой класс-оболочку, чтобы назвать тип устройства:
class hertz{
private:
unsigned int value;
hertz(){};
public:
operator unsigned int();
hertz(unsigned int value);
};
и решил позволить пользователю также использовать kHz:
class kilohertz{
private:
float value;
kilohertz(){};
public:
operator hertz();
kilohertz(float value);
};
в то время как функция внутри audio
класс, который позволяет пользователю задать частота дискретизации объявляется как track& samplingRate(units::hertz rate);
. Пользователь должен вызвать его, явно говоря, какой порядок величины он использует:
someAudioFile.samplingRate(hertz(44100));
someAudioFile.samplingRate(kilohertz(44.1));
мой вопрос:
есть ли лучший способ заставить пользователя использовать блок измерения простым и элегантным способом? Может быть, шаблон дизайна или какое-то умное использование typedefs?
Также обратите внимание, что в процессе создания двигателя мне может потребоваться больше единиц, которые будут несовместимы с Герц. Из верхней части моей головы я хочу, чтобы пользователь мог установить цвет пикселя как делать units::rgb(123,42,120)
и units::hsl(10,30,240)
.
я попытался найти жизнеспособный ответ и нашел только этот вопрос, но OP только хотел порядки величины без обеспечения того, что единицы не совместимы с другими.
Также обратите внимание, что я использую старый C++
версия, а не C++11
. Хотя размещение решения, действительного в любой версии, отлично, это было бы приятно, если бы я мог также использовать его:)
3 ответов
Я знаю, что вы упомянули, что не используете C++11, но другие, кто смотрит на этот вопрос, могут быть, поэтому вот решение C++11 с использованием пользовательских литералов:
#include <iostream>
using namespace std;
class Frequency
{
public:
void Print() const { cout << hertz << "Hz\n"; }
explicit constexpr Frequency(unsigned int h) : hertz(h) {}
private:
unsigned int hertz;
};
constexpr Frequency operator"" _Hz(unsigned long long hz)
{
return Frequency{hz};
}
constexpr Frequency operator"" _kHz(long double khz)
{
return Frequency{khz * 1000};
}
int main()
{
Frequency(44100_Hz).Print();
Frequency(44.1_kHz).Print();
return 0;
}
выход:
44100Hz
44100Hz
библиотека Boost "Units" отлично подходит для этого типа вещей.
http://www.boost.org/doc/libs/1_55_0/doc/html/boost_units.html
можно использовать дизайн завод шаблон выполнить то, что вы ищете. Можно создать частотный класс с частным конструктором и несколькими статическими методами, которые будут создавать объект в зависимости от единиц, которые пользователь хочет использовать. Сохраняя конструктор частным, пользователь вынужден объявлять свои единицы явно, что снижает вероятность ошибки пользователя.
#include <iostream>
using namespace std;
class frequency
{
public:
static frequency hertz(int hz)
{
return frequency(hz);
}
static frequency kilohertz(double kHz)
{
return frequency(kHz * KHZ_TO_HZ);
}
static frequency rpm(int rpm)
{
return frequency(rpm * RPM_TO_HZ);
}
int hz()
{
return m_hz;
}
private:
static const int KHZ_TO_HZ = 1000;
static const int RPM_TO_HZ = 60;
frequency(int hz) : m_hz(hz)
{
}
int m_hz;
};
int main()
{
wcout << frequency::hertz(44100).hz() << "Hz" << endl;
wcout << frequency::kilohertz(44.100).hz() << "Hz" << endl;
}