шаблоны проектирования — единицы измерения в переполнении стека

Я работаю над игровым движком, и в настоящее время я застрял в разработке системы ввода-вывода. Я сделал это так, сам двигатель не справляется любой форматы файлов, но позволяет пользователю реализовать все, что он хочет, создав *.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, Хотя публикация решения, действительного в любой версии, — это здорово, было бы неплохо, если бы я тоже мог его использовать 🙂

13

Решение

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

http://ideone.com/UzeafE

#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
22

Другие решения

Библиотека Boost «Units» отлично подходит для такого рода вещей.

http://www.boost.org/doc/libs/1_55_0/doc/html/boost_units.html

8

Вы можете использовать фабричный дизайн чтобы выполнить то, что вы ищете. Вы можете создать класс частоты с помощью частного конструктора и нескольких статических методов, которые будут создавать объект в зависимости от единиц измерения, которые пользователь хочет использовать. Сохраняя конструктор закрытым, пользователь вынужден явно объявлять свои единицы измерения, что снижает вероятность ошибки пользователя.

#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;
}
4
По вопросам рекламы [email protected]