Rzućmy okiem na konkretnych funkcjach pierwsze:Uboczny referencje przekazując wątku klasy otoki
void boo1() { std::cout << "boo1\n"; }
void boo2 (std::string) { std::cout << "boo2\n"; }
struct X {
void boo3() { std::cout << "boo3\n"; }
void boo4 (std::string) { std::cout << "boo4\n"; }
};
Chcę te funkcje mają być wykonane z jakiejś funkcji „strażnika”, który robi ochronę wyjątku (wyjaśnienie poniżej). Tak, napisałem dwie funkcje jeden z bezpłatnych funkcji, a inne dla funkcji składowych:
template <typename C, typename... Args>
typename std::enable_if<!std::is_member_function_pointer<C>::value, void>::type
foo (C&& c, Args&&... args) {
std::cout << "not memfun\n";
c (std::forward<Args> (args)...);
}
template <typename C, typename T, typename... Args>
typename std::enable_if<std::is_member_function_pointer<C>::value, void>::type
foo (C&& c, T* o, Args&&... args) {
std::cout << "memfun\n";
(o->*c) (std::forward<Args> (args)...);
}
a teraz chcę wykonać boo1()
, boo2()
, X::boo3()
i X::boo4()
w nowych wątków, ale z „ochrony” używanego przez foo()
funkcji . Tak, bez problemu mogę to zrobić:
X x;
std::thread th1 {&foo<void (*)()>, &boo1};
std::thread th2 {&foo<void (*) (std::string), std::string>, &boo2, "Hello"};
std::thread th3 {&foo<void (X::*)(), X>, &X::boo3, &x};
std::thread th4 {&foo<void (X::*) (std::string), X, std::string>, &X::boo4, &x, "Hello"};
So, idąc krok dalej napisałem wątek klasy otoki do zaprzestania używania wyraźnie std::join()
lub std::detach()
. Zainstalowana jedna z nich jest wywoływana, gdy destruktor jest w akcji. Dla uproszczenia tego przykładu użyłem tylko jednego z nich. Więc, kod wygląda następująco:
class Th {
public:
template <typename C,
typename = typename std::enable_if<!std::is_member_function_pointer<C>::value, void>::type,
typename... Args>
Th (C&& c, Args... args) // (X)
: t {foo<C, Args...>, std::forward<C> (c), std::forward<Args> (args)...} {}
template <typename C,
typename = typename std::enable_if<std::is_member_function_pointer<C>::value, void>::type,
typename T,
typename... Args>
Th (C&& c, T* o, Args... args) // (Y)
: t { foo<C, T, Args...>, std::forward<C> (c), o, std::forward<Args> (args)...} {}
~Th() { t.join(); }
private:
std::thread t;
};
I z tej implementacji nie ma problemu, następujące przypadki użycia:
X x;
Th h1 {&boo1};
Th h2 {&boo2, "Hello"};
Th h3 {&X::boo3, &x};
Th h4 {&X::boo4, &x, "Hello"};
praca jako excepcted. Jest jednak jedna wada - nie ma idealnego przekazania. Jeśli zmienię w (X)
i (Y)
Args...
do Args&&...
który jest pożądany, kod nie skompilować z pewnymi błędami, jeden z nich to:
error: no type named ‘type’ in ‘class std::result_of<void (*(void (*)(std::basic_string<char>), const char*))(void (*&&)(std::basic_string<char>), const char (&)[6])>’
który jeśli rozumiem go poprawnie, std::bind()
w std::thread
konstruktora nie można zrobić to jest praca, albo popraw mnie, jeśli się mylę.
Moje pytanie brzmi: co mogę zrobić, aby skorzystać z idealnego przekazywania w tym przypadku?
Kompilatorem użytym do skompilowania tego pliku był GCC 4.8.1.
Promised wyjaśnienie: Chcę foo()
funkcje otoczyć wywołanie c()
z try
i catch
, aby upewnić się, że wyjątek jest przechwycony, proces tę informację w jakiś mechanizm rejestrowania i przekaż wyjątek w razie potrzeby z przejrzystości dla użytkownika klasy Th
.
Interesujące. Nie uda się skompilować, jeśli uruchomię go z 'std :: string (" Hello ")' zamiast zwykłym '" Hello "' w 'h2' i' h4'. Błąd polega na "nieznanej konwersji z 'std :: __ cxx11 :: basic_string' na 'std :: __ cxx11 :: basic_string &&' dla pierwszego argumentu auto forward_to_thread (T && t)' ('clang 5.0'). –
cantordust
Argumenty 'forward_to_thread' również powinny zostać przekazane, naprawione. Dzięki. – krzaq
To jest świetne, dziękuję –