2

I want to run my minimax algorithm async so it doesn't freeze the ui while waiting for a turn. Here is the static method i need to call:

//ChessContext is the current state of the board
//Turn contains fromX, fromY, toX, toY when moving a piece
static Turn getBestTurn(ChessContext cc, int depth);

I have tried this:

//context is a reference to the game currently played
auto fu = std::async(std::launch::async, ChessContext::getBestTurn, context , 5);
Turn t = fu.get();

It's giving me an error saying

boardview.cpp:69:23: error: no matching function for call to 'async' 
future:1712:5: note: candidate template ignored: substitution failure [with _Fn = Turn (&)(ChessContext, int), _Args = <ChessContext &, int>]:
    no type named 'type' in 'std::result_of<Turn ((ChessContext, int))(ChessContext, int)>'
future:1745:5: note: candidate template ignored: substitution failure [with _Fn = std::launch, _Args = <Turn (&)(ChessContext, int), ChessContext &, int>]:
    no type named 'type' in 'std::result_of<std::launch (Turn ()(ChessContext, int), ChessContext, int)>'

I eventually want to run the algorithm on every possible turn on a separate thread, or on two threads at a time to see if it gives me a performance increase.

Minimal code:

#include <iostream>
#include <thread>
#include <future> 

class Turn
{
};
class ChessContext 
{
public:
    ChessContext();
    ChessContext(ChessContext &cc);

    static Turn getBestTurn(ChessContext cc, int depth);
}; 

int main(){
    ChessContext context;
    auto fu = std::async(std::launch::async, ChessContext::getBestTurn, context, 5);
}

Here is the full project https://github.com/zlatkovnik/Super-Chesster.git

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
zlatkovnik
  • 23
  • 5
  • Did you remember to `#include ` ? – Jesper Juhl Jan 18 '20 at 12:52
  • What's the error you're getting? – super Jan 18 '20 at 12:54
  • @JesperJuhl Yes I included both future and thread. – zlatkovnik Jan 18 '20 at 12:55
  • 2
    When asking about build-errors, always include the *full* and *complete* error output, as it usually includes hint as to what the problem could be. Copy-paste (as text!) the error output into the question. Also please take some time to refresh [how to ask good questions](http://stackoverflow.com/help/how-to-ask), as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Jan 18 '20 at 12:55
  • @super boardview.cpp:69:23: error: no matching function for call to 'async' future:1712:5: note: candidate template ignored: substitution failure [with _Fn = Turn (&)(ChessContext, int), _Args = ]: no type named 'type' in 'std::result_of' future:1745:5: note: candidate template ignored: substitution failure [with _Fn = std::launch, _Args = ]: no type named 'type' in 'std::result_of' – zlatkovnik Jan 18 '20 at 12:55
  • 3
    can't reproduce: https://godbolt.org/z/sU2wBf please provide a [mre] – Alan Birtles Jan 18 '20 at 13:03
  • Make `getBestTurn` to be public, not private. – rafix07 Jan 18 '20 at 13:14
  • works for me: https://godbolt.org/z/m7AKn- – Alan Birtles Jan 18 '20 at 13:17
  • Sorry I needed a bit of guidance on how to post. I'll make sure to be more concise with my questions in the future. Thanks for the tips. – zlatkovnik Jan 18 '20 at 13:18
  • @walnut I'm using qtCreator for the project, I don't know if that has anything to do with the error. – zlatkovnik Jan 18 '20 at 13:19
  • Try calling the `getBestTurn` normally. Do you still get an error? Then the problem is most likely not to do with `std::async`, but something else (like `ChessContext` not being copyable). – Some programmer dude Jan 18 '20 at 13:22
  • @walnut I didn't try this simplified code yet – zlatkovnik Jan 18 '20 at 13:27
  • @Someprogrammerdude I have a copy constructor for ChessContext – zlatkovnik Jan 18 '20 at 13:27
  • I have shared the full project, the class where I call the async method is boardview.cpp. Bare in mind I still lacks a lot of functionality. – zlatkovnik Jan 18 '20 at 13:42
  • @zlatkovnik Unfortunately posting a link to your project does not make the question valid. You need to create a [mcve] if you want this re-opened. – super Jan 18 '20 at 13:44
  • I would suggest you check what compiler (and version) is being used. In qtCreator you can find that under `Tools > Options > Kits > Compilers`. – super Jan 18 '20 at 13:53

3 Answers3

2

ChessContext is not copyable. ChessContext(ChessContext &cc) is not a copy constructor, you need ChessContext(const ChessContext &cc).

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
1

Your minimal example compiles fine.

Your actual code in addition has this:

    ChessContext(ChessContext &cc);

This is not a normal copy constructor. A copy constructor usually take the argument by a const reference.

Here's a minimal example that reproduces your issue:

#include <future>

struct A {
    A() {}
    A(A&) {}
};

void test(A) {}

int main() {
    A a;
    test(a); // OK
    std::async(std::launch::async, &test, a); // Not OK
}

This is because std::launch::async copies the arguments, and a non-const reference does not bind to temporaries.

To fix, change the copy constructor to

    ChessContext(ChessContext const &cc);
rustyx
  • 80,671
  • 25
  • 200
  • 267
0

You can use lambda to make life easier here:

auto fu = std::async(std::launch::async, [&]() { ChessContext::getBestTurn(context , 5); });

As for multithreading, a worker thread for the minimax is advisable, but in real scenarios since you will be needing hashtable and other stuffs, to allow force moves or undo move etc, separate thread for each depth search is not recommended.

ark1974
  • 615
  • 5
  • 16
  • Now that line is good, but it gives me this error on fu.get(); boardview.cpp:70:18: error: no viable conversion from 'void' to 'Turn' turn.h:13:5: note: candidate constructor not viable: cannot convert argument of incomplete type 'void' to 'const Turn &' for 1st argument – zlatkovnik Jan 18 '20 at 13:32
  • this needs a return inside the lambda and is unlikely to solve the problem anyway – Alan Birtles Jan 18 '20 at 13:34
  • You need to check if `fu` is ready befiore calling `fu.get()` – ark1974 Jan 18 '20 at 13:35
  • Anyhow, use of std::future is not going to help you here as it is going to block the main UI thread, consider using other viable options like std::atomic or std::conditional_variable with std::mutex – ark1974 Jan 18 '20 at 13:37