Я работаю над игровым движком, и в настоящее время я застрял в разработке системы ввода-вывода. Я сделал это так, сам двигатель не справляется любой форматы файлов, но позволяет пользователю реализовать все, что он хочет, создав *.dll
файл с соответствующими именами функций внутри. Хотя это само по себе не было большой проблемой, мои главные проблемы — это последствия, которые, вероятно, будут видны при использовании двигателя.
Я разработал простой resource
интерфейс как базовый класс для всего, о чем может думать пользователь, и я пытаюсь расширить его, создавая простые дочерние классы, предназначенные для общих типов данных, чтобы пользователю не приходилось реализовывать основы самостоятельно (в настоящее время Я думал о audio
, image
, data
а также mesh
). Начиная с audio
класс, я наткнулся на специфическую проблему, пытаясь решить, в каком типе я должен хранить информацию о частота выборки. Обычный блок герц, поэтому я решил сделать это unsigned int
,
Однако здесь есть небольшая проблема — что если пользователь попытается установить его в килогерц? Давайте предположим, что какой-то абстрактный формат файла может на мгновение сохранить его в обоих блоках. Я сделал простой класс-обертку для имени типа модуля:
class hertz{
private:
unsigned int value;
hertz(){};
public:
operator unsigned int();
hertz(unsigned int value);
};
и решил позволить пользователю также использовать кГц:
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
, Хотя публикация решения, действительного в любой версии, — это здорово, было бы неплохо, если бы я тоже мог его использовать 🙂
Я знаю, что вы упомянули, что вы не используете 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;
}