В случае, если ваш this
известен во время компиляции, тогда статическое метапрограммирование для спасения.
C ++, Swift и Rust (и теперь также Scala) являются статическими языками, которые имеют много компиляциивремя для решения подобных проблем.
Как?В вашем случае шаблоны могут вам помочь.
Кроме того, вам не нужно, чтобы это была функция-член, это может быть функция друга (так что вы можете легко использовать шаблоны).
class A
{
public:
template<typename T>
friend void StartThreads(const T& obj);
protected:
virtual void FooFunc()
{
while (true)
std::cout << "hello\n";
}
};
template<typename T>
void StartThreads(const T& obj) {
std::thread fooThread(&T::FooFunc, obj);
fooThread.join();
}
ПРЕДУПРЕЖДЕНИЕ: Этот ТОЛЬКО работает, если класс известен во время компиляции, т.е.
class B: public A {
};
...
B b;
A &a = b;
StartThreads(a); // Will call it AS IF IT IS A, NOT B
Другое решение:
Функциональное программирование для спасения, вы можете использовать лямбды (или функторы, использующие структуры, если вы находитесь на C ++ до C ++ 11)
C ++ 11:
void StartThreads()
{
std::thread fooThread([=](){ this->FooFunc(); });
fooThread.join();
}
C ++ 98:
// Forward declaration
class A;
// The functor class (the functor is an object that is callable (i.e. has the operator (), which is the call operator overloaded))
struct ThreadContainer {
private:
A &f;
public:
ThreadContainer(A &f): f(f) {}
void operator() ();
};
class A
{
public:
// To allow access of the protected FooFunc function
friend void ThreadContainer::operator() ();
void StartThreads()
{
// Create the functor
ThreadContainer a(*this);
// Start the thread with the "call" operator, the implementation of the constructor tries to "call" the operand, which here is a
std::thread fooThread(a);
fooThread.join();
}
protected:
virtual void FooFunc()
{
while (true)
std::cout << "hello\n";
}
};
class B: public A {
protected:
virtual void FooFunc() {
while(true)
std::cout << "overridden\n";
}
};
void ThreadContainer::operator() () {
f.FooFunc();
}