Pull to refresh

Практическое применение шаблона с переменным количеством параметров для самых маленьких

Пролог


Недавно у меня появилась потребность применить на практике такую вещь, как variadic templates. Нашел я пару статей здесь, на Хабре. Вот к примеру достаточно хорошая, чтобы познакомиться з тем, что же это за технология и как это работает.


Только проблема была в том, что первый же пример у меня не компилился с помощью MSVS компилятора (компилятор, встроенный в Visual Studio), а остальные нуждались в дополнительных библиотеках, которые нужно было скачать и прикрутить к проекту. К тому же, даже первый пример покажется слишком сложным новичку (как, например, он сперва показался мне :) ), поэтому я решил написать эту статью...


От слов к делу


Проблема

Есть много различных методов и фунций, которые нуждаются в многократном повторении выполнения до тех пор, пока не выполнится какое либо условие ИЛИ не выйдет их время. Например, функция проверяет, появилось ли какое нибудь окно на рабочем столе не больше 5 секунд, и как только оно появилось, возвращает результат. Проще говоря, нужна функция-таймер, которая будет принимать другую функцию и выполнять ее на протяжении данного времени. Главная проблема здесь — универсальность.


Постановка задачи

Делаем функцию, которая будет принимать на вход указатель на другую функцию(с возвращаемым типом bool), время(тайм-аут), и выполнять ее, пока функция-аргумент не вернет true или не истечет время.


Реализация

Приведу самый простой (на мой взгляд) пример реализации, который работает у меня в VS 2015 с конфигом Platform toolset: Visual Studio 2015(v140).


/* Пример */

#include <Windows.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

// Магия тут
// Самое сложное здесь - правильно обьявить указатель на функцию
template <typename ... Args>
bool smartWaiter(DWORD timeout, bool(*func)(Args ...), Args ... args) // Таймаут, указатель, аргументы
{
    DWORD start = ::GetTickCount(); //старт отчета
    bool result = func(args ...); 
    while (!result && ::GetTickCount() - start < timeout) // условие: пока не получим true или жє пока время не выйдет
        result = func(args ...);

    return result; // если время закончится и будет false, мы вернем false, а если выйдем преждевременно, то получим true
}

// Дальше просто примеры функций
bool someFunc(int a, const char* str, char* x)
{
    // some operations which depend on time/state
    return true;
}

bool someAnotherFunc(const char* b)
{
    // some operations which depend on time/state
    return true;
}

bool someVoidFunc()
{
    // some operations which depend on time/state
    return true;
}

int main()
{
    const DWORD DEFAULT_TIMEOUT = 1000; // 1000 милисекунд, что равно 1 секунде

    bool result;
    std::vector<bool> results;

    // и немножно магии тут, главное здесь - правильно специализировать шаблон, а дальше уже
    // через запятую передать тот же таймер, указатель, ну и затем параметры, типы которых мы указали
    result = smartWaiter <int, const char*, char*>(DEFAULT_TIMEOUT, someFunc, 1, "Yeap", "x");
    results.push_back(result);

    result = smartWaiter <const char*>(DEFAULT_TIMEOUT, someAnotherFunc, "Yeap");
    results.push_back(result);

    // можно вызывать и функицю без параметров
    result = smartWaiter<>(DEFAULT_TIMEOUT, someVoidFunc);
    results.push_back(result);

    // просто вывод возвращаемых результатов
    // чтобы показать, что функция действительно была вызвана
    std::copy(results.begin(), results.end(), std::ostream_iterator<bool>(std::cout, " \n"));

    system("pause");
}

Эпилог


С этим можно еще много эксперементировать, в частности, сделать возвращаемый тип R вместо bool, но тогда следует предусмотреть реализацию сравнения результата, чтобы знать, когда мы должны возвратить его преждевременно.


Надеюсь, Вам было приятно это читать и, самое главное, полезно.

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.