无法将对抽象 class 的引用传递给线程函数?
Reference to abstract class can't be passed to thread function?
我想在使用 std::thread
调用的函数中使用对抽象 class (A
) 的引用作为参数类型。
这似乎是不可能的,因为编译器出于某种原因尝试编译:std::tuple<A>
,即使在我的代码中只有 A
的引用类型被用作参数(从不作为值类型)。
#include <cstdlib>
#include <thread>
class A {
public:
virtual void a() = 0;
};
class B : public A {
public:
virtual void a() {
}
};
class C {
public:
C(A& aRef) {
thread = std::thread(&C::doSomething, this, aRef);
}
private:
void doSomething(A& aRef) {
}
std::thread thread;
};
int main(int argc, char* argv[]) {
B b;
C c(b);
return EXIT_SUCCESS;
}
将在 Visual Studio 2017 年输出:
error C2259: 'A': cannot instantiate abstract class
tuple(278): note: see reference to class template instantiation 'std::tuple<A>' being compiled
tuple(278): note: see reference to class template instantiation 'std::tuple<C *,A>' being compiled
thread(49): note: see reference to class template instantiation 'std::tuple<void (__thiscall C::* )(A &),C *,A>' being compiled
main.cpp(18): note: see reference to function template instantiation 'std::thread::thread<void(__thiscall C::* )(A &),C*const ,A&,void>(_Fn &&,C *const &&,A &)' being compiled
为什么 std::thread
尝试编译 std::tuple<A>
?如果我直接从主线程调用 C::doSomething
,代码编译正常。
这里有什么我遗漏的吗?
当您将引用作为参数传递给您的线程时,您需要将引用包装在 std::reference_wrapper
中。
您可以使用 std::ref()
来做到这一点。
看看这个例子:
#include <thread>
#include <utility>
#include <iostream>
struct A {
virtual void a() = 0;
};
struct B : public A {
virtual void a() { std::cout << "Hello World\n"; }
};
class C {
void doSomething(A& aRef) { aRef.a(); }
std::thread thread;
public:
C(A& aRef) : thread(&C::doSomething, this, std::ref(aRef)) {}
// or alternatively using a lambda:
//C(A& aRef) : thread( [&](){ doSomething(aRef); } ) {}
void join() { thread.join(); }
};
int main(int argc, char* argv[]) {
B b;
C c(b);
c.join();
}
这样编译运行:
$ g++ ~/tt.cc -std=c++11 -pthread && ./a.out
Hello World
供参考:
我想在使用 std::thread
调用的函数中使用对抽象 class (A
) 的引用作为参数类型。
这似乎是不可能的,因为编译器出于某种原因尝试编译:std::tuple<A>
,即使在我的代码中只有 A
的引用类型被用作参数(从不作为值类型)。
#include <cstdlib>
#include <thread>
class A {
public:
virtual void a() = 0;
};
class B : public A {
public:
virtual void a() {
}
};
class C {
public:
C(A& aRef) {
thread = std::thread(&C::doSomething, this, aRef);
}
private:
void doSomething(A& aRef) {
}
std::thread thread;
};
int main(int argc, char* argv[]) {
B b;
C c(b);
return EXIT_SUCCESS;
}
将在 Visual Studio 2017 年输出:
error C2259: 'A': cannot instantiate abstract class
tuple(278): note: see reference to class template instantiation 'std::tuple<A>' being compiled
tuple(278): note: see reference to class template instantiation 'std::tuple<C *,A>' being compiled
thread(49): note: see reference to class template instantiation 'std::tuple<void (__thiscall C::* )(A &),C *,A>' being compiled
main.cpp(18): note: see reference to function template instantiation 'std::thread::thread<void(__thiscall C::* )(A &),C*const ,A&,void>(_Fn &&,C *const &&,A &)' being compiled
为什么 std::thread
尝试编译 std::tuple<A>
?如果我直接从主线程调用 C::doSomething
,代码编译正常。
这里有什么我遗漏的吗?
当您将引用作为参数传递给您的线程时,您需要将引用包装在 std::reference_wrapper
中。
您可以使用 std::ref()
来做到这一点。
看看这个例子:
#include <thread>
#include <utility>
#include <iostream>
struct A {
virtual void a() = 0;
};
struct B : public A {
virtual void a() { std::cout << "Hello World\n"; }
};
class C {
void doSomething(A& aRef) { aRef.a(); }
std::thread thread;
public:
C(A& aRef) : thread(&C::doSomething, this, std::ref(aRef)) {}
// or alternatively using a lambda:
//C(A& aRef) : thread( [&](){ doSomething(aRef); } ) {}
void join() { thread.join(); }
};
int main(int argc, char* argv[]) {
B b;
C c(b);
c.join();
}
这样编译运行:
$ g++ ~/tt.cc -std=c++11 -pthread && ./a.out
Hello World
供参考: