使用SFML与std::thread调用类成员函数的编译错误排查
Hey there! Let's work through those compilation errors you're hitting when trying to use threads for your laser firing logic in SFML. I'll break down the root causes and show you exactly how to fix things.
What's Causing the Compilation Errors?
The two result_of errors you're seeing boil down to incorrect parameter handling when creating your std::thread. Here's the key issue:
- Your
lasers::firefunction expects references forTexture&andFloatRect&, but when you pass these parameters tostd::thread, it defaults to copying them into the thread's context. This creates a type mismatch—your function is looking for a reference, but the thread is trying to pass a copied value. The compiler can't resolve this mismatch, hence the confusing "no type named 'type'" errors.
Step-by-Step Fixes
1. Wrap Reference Parameters with std::ref()
When creating your thread, you need to explicitly tell the compiler to pass references instead of copying values. Use std::ref() for any parameters that your fire function takes by reference:
// Updated thread creation in main() if(Keyboard::isKeyPressed(Keyboard::Space)) { if(j == 0) { // Wrap reference parameters with std::ref() to preserve reference type std::thread th(&lasers::fire, &zxcv, std::ref(t5), std::ref(boundingBoxBORDER), sPlayer.getPosition()); // Detach the thread so it runs independently (join would block your game loop) th.detach(); j = 1; } }
2. Reset Laser State After Movement
Right now, once you fire once, ok2 stays set to 1 and you can't fire again. Add a line to reset ok2 after the laser finishes moving to re-enable firing:
void fire(Texture &t5, FloatRect bbBG, Vector2f pP) { if(ok2 != 1) { sLaser.setTexture(t5); sLaser.setOrigin(1,-705); sLaser.setPosition(pP.x+20.5,pP.y+645); sLaser.scale(0.1f,0.1f); ok2 = 1; } while(sLaser.getGlobalBounds().intersects(bbBG)) { sLaser.move(0,-2); // Use standard C++ thread sleep instead of SFML's for better compliance std::this_thread::sleep_for(std::chrono::milliseconds(10)); } ok2 = 0; // Reset state to allow future laser fires }
3. Critical Note: SFML Thread Safety
A quick heads-up: SFML's Sprite and rendering objects are not thread-safe. If your main game thread is rendering the laser sprite at the same time your worker thread is modifying its position, you might get weird glitches or crashes.
A more robust approach is to separate data updates from rendering:
- Add a
Vector2f laserPositionmember to yourlasersclass - In the worker thread, update only
laserPositioninstead of modifying the sprite directly - In your main game loop's render step, sync the sprite's position to
laserPosition
Example of this adjusted setup:
// Updated lasers class class lasers { public: Sprite sLaser; Vector2f laserPosition; int ok2=0; void fire(Texture &t5, FloatRect bbBG, Vector2f pP) { if(ok2 != 1) { sLaser.setTexture(t5); sLaser.setOrigin(1,-705); laserPosition = {pP.x+20.5, pP.y+645}; sLaser.setPosition(laserPosition); sLaser.scale(0.1f,0.1f); ok2 = 1; } while(sLaser.getGlobalBounds().intersects(bbBG)) { laserPosition.y -= 2; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } ok2 = 0; } }; // In your main game loop's render section: zxcv.sLaser.setPosition(zxcv.laserPosition); app.draw(zxcv.sLaser);
Final Check
After making these changes, your code should compile successfully, and your laser sprite will move upward until it exits the bounds—all running in a separate thread so it doesn't block your main game loop.
内容的提问来源于stack exchange,提问作者Alexander

