ErrorCode error = ERROR_NO;
try
{
EnumConverter
conv.convert (driverType, {sensor::DriverType::Simulation, sensor::DriverType::Usb, sensor::DriverType::Ethernet}); // (6)
if (conv.error())
{
return ERROR_INVALID_ARGUMENT;
}
switch (conv.result()) // (7)
{
case sensor::DriverType::Simulation:
{
CreateDriver(sensor::DriverType::Simulation, g_DriverSimulation);
}
break;
case sensor::DriverType::Usb:
{
CreateDriver(sensor::DriverType::Usb, g_DriverUSB);
}
break;
case sensor::DriverType::Ethernet:
{
CreateDriver(sensor::DriverType::Ethernet, g_DriverEthernet);
}
break;
}
}
catch (sensor::sensor_exception& e)
{
error = static_cast
}
return error;
}
В строках 1–3 объявляются указатели для хранения классов всех возможных типов драйверов. В строке 4 объявлена вспомогательная функция для создания драйвера. Эта функция проверяет, создан ли драйвер соответствующего типа, при необходимости создает, инициализирует и передает его в интерфейсный класс.
В строке 5 приведена реализация интерфейсной функции для настройки драйвера. В строке 6 конвертируется переданное числовое значение в перечисление C++ (будет рассмотрено ниже). В строке 7 объявлен оператор switch, в котором анализируется полученное значение перечисления, и вызывается вспомогательная функция с соответствующими параметрами.
В функции API для задания типа драйвера используются числовые значения, а в интерфейсном классе используются перечисления C++. Для того, чтобы сконвертировать числовое значение в перечисление, используется вспомогательный класс EnumConverter (Листинг 109)
template
class EnumConverter
{
public:
template
void convert(ConvValueType value, std::initializer_list
{
isError_ = true;
for (Enum item : list) // (4)
{
if (static_cast
{
result_ = item; // (6)
isError_ = false;
break;
}
}
};
bool error() const { return isError_; }
Enum result() const { return result_; }
private:
bool isError_;
Enum result_;
};
В строке 1 объявлен шаблонный класс, параметром которого является тип перечисления. Конвертация происходит в функции 2, которая объявлена в виде шаблона, параметром шаблона является тип числового значения для конвертации. Функция принимает число, которое должно быть сконвертировано, а также список значений перечисления (строка 3). Реализация пробегает по всем элементам списка (строка 4) и, если какой-то из элементов списка перечисления равен переданному значению, запоминает это значение перечисления в качестве результата (строки 5,6).
6.3.6. Обратные вызовы
Касательно обратных вызовов мы имеем следующую ситуацию. В системном API контекст вызова передается с помощью указателей на данные, по-другому организация передачи контекста здесь невозможна (см. п. 2.1.2). В интерфейсном классе указатель на данные не используется, поскольку в C++ имеется множество гораздо более изящных способов передачи контекста. Вот тут-то нам и понадобится перенаправление вызовов (см. п. 4.6.2). Реализация одной из интерфейсных функций API, использующей перенаправление вызовов, приведена в Листинг 110.
ErrorCode readSensorValues(SensorValueCallback callback, void* pContextData)
{
ErrorCode error = ERROR_NO;
try
{
using namespace std::placeholders;
g_SensorControl->readSensorValues(std::bind(callback,_1,_2,pContextData)); // (1)
}
catch (sensor::sensor_exception& e)
{