Как создать поток с параметром функции внутри функции (C ++, Visual Studio 2017)? - PullRequest
0 голосов
/ 04 ноября 2018

Я пытаюсь создать класс с именем ThreadMaster, который безопасно обрабатывает все потоки в приложении. Я хочу иметь возможность добавить поток с любой функцией в ThreadMaster, поэтому мне нужно использовать va_list (или что-то подобное). Однако конструктор потока не принимает va_list в качестве аргумента (я думаю). Я сделал следующий код, чтобы проверить это:

#include <thread>
#include <vector>
#include <cstdarg>

using namespace std;

void fee(int i) {}
void foo() {}

class ThreadMaster {
public:
    vector<thread> threads;
    /*void add(...) {
        va_list args;
        threads.push_back(thread(args));
    }*/
};

ThreadMaster tm;

void add(void(*func)()) {
    tm.threads.push_back(thread(func));
}

void edd(void(*func)(int), int x) {
    tm.threads.push_back(thread(func, x));
}

/*void odd(...) {
    va_list args;
    thread t(args);
    t.join();
}*/

int main() {
    add(foo);
    edd(fee, 6);

    tm.threads[0].join();
    tm.threads[1].join();
}

Когда я закомментирую нечетную (...) функцию, она компилируется и запускается без ошибок, но когда она появляется, я получаю следующую ошибку:

.../xthread(238): error C2672: 'std::invoke': no matching overloaded function found

Самым странным и раздражающим является то, что функция ThreadMaster :: add () раньше компилировалась и работала нормально, только когда я откатился от создания функции join_all, я получил эту ошибку. Я понятия не имею, почему.

Как передать мои аргументы моему ThreadMaster? Я хочу сделать потоки частными, поэтому мне нужно сделать это через функцию ThreadMaster :: add (). Я настоятельно предпочитаю не устанавливать какие-либо нестандартные библиотеки. Если ошибка вызвана какой-то настройкой в ​​VS, что я каким-то образом ошибся, это было бы предпочтительным решением.

Заранее спасибо за помощь.

- РЕДАКТИРОВАТЬ -

После комментариев я создал следующий шаблон в tester.h:

class ThreadMaster {
public:
    vector<thread> threads;
    void add(void(*func)()) {
        threads.push_back(thread(func));
    }
    template<class T>
    void add(void(*func)(T), T t) {
        threads.push_back(thread(func, t));
    }
    template<class T, class S>
    void add(void(*func)(T, S), T t, S s) {
        threads.push_back(thread(func, t, s));
    }
};

И tester.cpp теперь это:

#include <thread>
#include <vector>
#include <cstdarg>

using namespace std;

#include "tester.h"

void fee(int i) {}
void foo() {}

ThreadMaster tm;

void add(void(*func)()) {
    tm.add(func);
}

void edd(void(*func)(int), int x) {
    tm.add(func, x);
}

int main() {
    add(foo);
    edd(fee, 6);

    tm.threads[0].join();
    tm.threads[1].join();
}

Это работает и будет практическим решением, так как количество аргументов несколько ограничено. Однако это не реальное решение проблемы, поэтому я оставлю этот вопрос открытым.

1 Ответ

0 голосов
/ 05 ноября 2018

Похоже, вы хотите обертку для конструктора std::thread, чтобы вы могли хранить все объекты thread в определенном контейнере. Поэтому имеет смысл, чтобы ваша оболочка принимала те же аргументы, что и конструктор.

Взглянув на cppreference , кажется, что у конструктора # 3 есть нужная подпись:

template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );

Настройка вашей функции-члена на эту подпись:

template< class Function, class... Args >
void add( Function&& f, Args&&... args ) {
    threads.emplace_back(f, args...);
}

(Я также изменил push_back на emplace_back, поскольку в данном случае это выглядит более подходящим.) Я не проверял это дальше, чем проверял, что он компилируется, но принцип здравый: при создании оболочки , начните с копирования сигнатуры функции.

...