Я обертываю Windows API, и я хочу сделать проверку ошибок простой в использовании и полезной. В настоящее время у меня есть глобальный объект ошибки, с функцией set
для обработки новой ошибки. Функция set
принимает четыре аргумента: bool Error::set (const int code, const char * file, const char * const function, const int line);
Функция использует аргументы файла, функции и строки для отображения их в хорошо отформатированном сообщении.Обтекание любой функции API
Чтобы облегчить установку ошибок, существует макрос #define setError() error.set (GetLastError(), __FILE__, __FUNCTION__, __LINE__);
Таким образом, я могу в любой момент использовать setError()
, чтобы ответить на ошибку, которую установила функция API, добавив ее после вызова этой функции API.
К сожалению, это приводит к тому, код выглядит примерно так:
SomeAPIFunction();
setError();
AnotherAPIFunction();
setError();
Существует также проблема с конструкторами:
MyClass:MyClass()
: a (SomeAPIFunction), b (AnotherAPIFunction)
{
setError(); //what if both functions set an error?
}
Как вы можете видеть, используя синтаксис инициализации члена, я Фактически я ограничиваю себя.
Один из способов исправить это было бы обернуть все функции API:
int someAPIFunction()
{
int ret = SomeAPIFunction();
setError();
return ret;
}
function
часть сообщения об ошибке будет сказать мне, какая функция возникла ошибка. Конечно, это должен быть худший способ справиться с этим.
Решение, похоже, заключается в использовании вариативных шаблонов. Проблема в том, что я понятия не имею, что я должен делать, чтобы заставить их работать на это. Я бы себе представить окончательный код выглядит как один из следующих вариантов:
wrap<int, SomeAPIFunction (5)>();
wrap<int, SomeAPIFunction, 5>();
wrap<int, SomeAPIFunction> (5);
Я прочитал вещи начинают VARIADIC шаблоны, но они все оставили меня невежественный о том, как создать что-то вроде этого. Может ли кто-нибудь указать мне в правильном направлении?
Я нашел следующее на a similar question:
#include <iostream>
template<void f(void)>
struct Wrap {
void operator()() const {
std::cout << "Pre call hook" << std::endl;
f();
}
};
namespace {
void test_func() {
std::cout << "Real function" << std::endl;
}
}
const Wrap<&test_func> wrapped_test_func = {};
int main() {
wrapped_test_func();
return 0;
}
Ответчик отметил, что VARIADIC шаблоны была бы необходимость сделать это достаточно общий характер. Это начало, но я потерян и благодарен за любую помощь по этому вопросу.
Для начала не все функции API используют механизм GetLastError. И тогда, еще более хлопотно, можно только вызвать GetLastError, когда эти функции API сообщают об ошибке.Таким образом, код в вашем вопросе обречен на провал. –
Большинство функций API Win32 задают значение 'LastError' *, только если на самом деле была ошибка *. В случае успеха они оставляют значение «LastError» в одиночку. Есть исключения из этого; документация по Win32 API точно описывает, что делает каждая функция. –
Я знаю об этом. Если 'GetLastError' возвращает 0 (ERROR_SUCCESS), он игнорируется. Я знаю, что некоторые части также используют другие механизмы, но я пока не добавил к ним никакой поддержки. По мере того, как я продолжаю расширяться, я добавлю, что необходимо. Вызов 'SetLastError (0);' когда я закончу обработку этого в рамках подготовки к следующему вызову функции API, также является возможностью. – chris