В C ++, как добавить аргумент в список аргументов «Args && ... args»? - PullRequest
0 голосов
/ 10 мая 2018

У меня есть собственная реализация потоков, которая позволяет мне управлять различными способами общения с моими потоками.Он основан на классе C ++ std::thread.

Я создаю поток для запуска функции с именем run(), которая вызывает функцию пользователя.То, что я хотел бы сделать, это вызвать пользовательскую функцию, включая мой указатель объекта потока.

В конструкторе есть проблема.Я хочу передать Args, как указано в конструкторе, и добавить к этому списку this:

class safe_thread
{
public:
    typedef std::shared_ptr<safe_thread>    pointer_t;
    typedef std::vector<pointer_t>          vector_t;

    template<class Function, class... Args>
    safe_thread(Function&& f, Args&&... args)
        : f_function([this, f, args...]{ std::bind(f, this, args...)(); })
    {
[...snip...]

private:
    std::function<void()>               f_function;
};

// I use that constructor with two different types of signatures:
//
// 1. member function
//
safe_thread listen(&my_other_class::some_function, this);

// 2. static function
//
safe_thread worker(&my_static_function);

std::bind() не понимает мой текущий синтаксис.Ожидается функция (f) и args....Итак, как мне изменить args..., чтобы включить this?

1 Ответ

0 голосов
/ 11 мая 2018

Для тех, кто заинтересован, я действительно нашел решение, которое заключается в перемещении параметра this в конец списка.Таким образом, мои std::invoke() для функции-члена или стандартной статической функции работают одинаково:

f_function([this, f, args...]{ std::invoke(f, args..., this)(); })

Без этого, как упомянул Майлз Буднек, загрузке SFINAE потребуется знать, является ли fфункция-член или простая функция.

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

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

По сути, мойПервая попытка была сгенерирована следующим образом:

std::invoke(
    &my_other_class::some_func,     // correct
    safe_thread::this,              // wrong 'this' (i.e. safe_thread)
    my_other_class::this,           // 'this' for function, wrong location
    ...);                           // other parameters

Изменяя порядок в моем вызове, я теперь получаю правильное 'this' в правильном месте:

std::invoke(
    &my_other_class::some_func,     // correct
    my_other_class::this,           // 'this' for function, correct location
    ...,                            // other parameters
    safe_thread::this);             // 'this' to safe_thread

Очевидно, это означает, что у меня естьисправить сигнатуру вызываемых функций, но у меня все в порядке.


Как уже упоминалось tkausl, std::bind() не требуется.Смотрите комментарии для деталей об этом.При этом std::invoke() - это C ++ 17, поэтому, если вы все еще используете старую версию, вам, вероятно, придется придерживаться std::bind().

...