Pull to refresh

Comments 9

все блоки, которыми оперирует GCD объявлены как
void (^dispatch_block_t)(void)

Если вы уже используете лямбды, то зачем усложнять написание и чтение gcdpp_dispatch_async еще и параметрами?

ИМХО что-то на подобии такого будет на порядки читабельнее:
gcdpp::gcdpp_dispatch_async(gcdpp::gcdpp_dispatch_get_global_queue(gcdpp::GCDPP_DISPATCH_QUEUE_PRIORITY_HIGH) ,[=]{
   //  а вот здесь уже вызываем любую функцию с любым количеством параметров, например
  function(1, 2.0f, "Hello World");
} );
UFO just landed and posted this here
Можно и через бинд запоминать, но имхо если уже используется C++11, то лучше использовать лямбды — они как раз для этого и предназначены. Читабельность от этого только выиграет
Создавать фиктивную лямбду, перевызывающую функцию — это в некотором роде оверхед. В любом случае, создание решения, которое будет работать как с лямбдой, так и с обычной функцией — это то, что нужно для удовлетворения любых вкусов и то, чего ждут от библиотеки. :)
Если повнимательней присмотреться, то можно понять, что предложенный вами вариант будет работать без каких либо изменений.

class Clazz
{
    
public:
    
    std::string m_value;
    
    void Foo(int a, float b, const std::string& c)
    {
        std::cout<<a<<b<<c<<std::endl;
    };
};

typedef std::function<void(void)> task_t;

TEST(gcdppLib, Dispatch_05)
{
    std::shared_ptr<Clazz> clazz = std::make_shared<Clazz>();
    task_t task = std::bind(&Clazz::Foo, clazz, 1, 2.0f, "Hello World");
    gcdpp::gcdpp_dispatch_async(gcdpp::gcdpp_dispatch_get_global_queue(gcdpp::GCDPP_DISPATCH_QUEUE_PRIORITY_HIGH), task);
}


Но все равно спасибо за замечание, так как без вас вряд бы проверил такой вариант. ;-)
Я предложил бы подумать об использовании std::packaged_task:
— он стандартный. Голова о том как эмулировать variadic templates болит только у авторов стандартной библиотеки
— он может хранить результат (включая выброшенное исключение). Есть возможность ожидать результат выполнения — std::future
Довольно интерессное предложение. Но насколько я понял, избежать работы с variadic templates не получится. Возможно я что-то не так понял, но вот по быстрому набросал реализацию:

std::queue<std::packaged_task<void()>> queue;

template<class FUNCTION, class ...ARGS>
std::future<typename std::result_of<FUNCTION(ARGS...)>::type>
dispatch(FUNCTION &&f, ARGS &&...args) {
    std::packaged_task<typename std::result_of<FUNCTION(ARGS...)>::type()> task(std::bind(f,args...));
    auto future = task.get_future();
    queue.push(std::packaged_task<void()>(std::move(task)));
    return future;
}

std::function<void(int, float, std::string)> function = [](int a, float b, const std::string& c)
{
      EXPECT_TRUE(a == 1 && b == 2.0f && c == "Hello World");
};
    
auto future = dispatch(std::move(function), 1, 2.0f, "Hello World");
queue.back()();


Поправьте меня, если я не прав :-)
А это создает нам проблему — как же нам хранить задачи в одной очереди, если они разнотипные?
Немного позанудствую, Ваш класс gcdpp_t_i_task не абстрактный, а ответом на Ваш вопрос является type erasure :-)
А разве F_ARGS и T_ARGS не совпадают, это немного усложняет пример? Зачем их разделять?
Sign up to leave a comment.

Articles