#include <iostream>
using namespace std;
struct MultiCallToken
{
private:
bool inUse = false;
friend class MultiCallGuard;
};
// guards against multiple calls
class MultiCallGuard
{
public:
~MultiCallGuard()
{
if(token && free)
{
token->inUse = false;
}
}
operator bool()
{
if(token->inUse)
return false;
return token->inUse = free = true;
}
MultiCallGuard(const MultiCallGuard&) = delete;
MultiCallGuard& operator=(const MultiCallGuard&) = delete;
MultiCallGuard(MultiCallGuard&& g) : token(g.token), free(g.free)
{
g.token = nullptr;
}
MultiCallGuard& operator=(MultiCallGuard&& g)
{
token = g.token;
free = g.free;
g.token = nullptr;
}
private:
MultiCallGuard(MultiCallToken& token) : token(&token), free(false) {}
MultiCallToken* token;
bool free;
friend MultiCallGuard guard(MultiCallToken&);
};
MultiCallGuard guard(MultiCallToken& t)
{
MultiCallGuard g(t);
return g;
}
MultiCallToken fooToken;
MultiCallToken barToken;
void bar();
void foo()
{
if(auto g = guard(fooToken))
{
cout << "foo called\n";
bar();
}
}
void bar()
{
if(auto g = guard(barToken))
{
cout << "bar called\n";
foo();
}
}
int main()
{
cout << ">> explicit call to foo:\n";
foo();
cout << "\n>> explicit call to bar\n";
bar();
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKc3RydWN0IE11bHRpQ2FsbFRva2VuCnsKcHJpdmF0ZToKCWJvb2wgaW5Vc2UgPSBmYWxzZTsKCQoJZnJpZW5kIGNsYXNzIE11bHRpQ2FsbEd1YXJkOwp9OwoKLy8gZ3VhcmRzIGFnYWluc3QgbXVsdGlwbGUgY2FsbHMKY2xhc3MgTXVsdGlDYWxsR3VhcmQKewpwdWJsaWM6Cgl+TXVsdGlDYWxsR3VhcmQoKQoJewoJCWlmKHRva2VuICYmIGZyZWUpCgkJewoJCQl0b2tlbi0+aW5Vc2UgPSBmYWxzZTsKCQl9Cgl9CgkKCW9wZXJhdG9yIGJvb2woKQoJewoJCWlmKHRva2VuLT5pblVzZSkKCQkJcmV0dXJuIGZhbHNlOwoJCQkKCQlyZXR1cm4gdG9rZW4tPmluVXNlID0gZnJlZSA9IHRydWU7Cgl9CgkKCU11bHRpQ2FsbEd1YXJkKGNvbnN0IE11bHRpQ2FsbEd1YXJkJikgPSBkZWxldGU7CglNdWx0aUNhbGxHdWFyZCYgb3BlcmF0b3I9KGNvbnN0IE11bHRpQ2FsbEd1YXJkJikgPSBkZWxldGU7CglNdWx0aUNhbGxHdWFyZChNdWx0aUNhbGxHdWFyZCYmIGcpIDogdG9rZW4oZy50b2tlbiksIGZyZWUoZy5mcmVlKQoJewoJCWcudG9rZW4gPSBudWxscHRyOwoJfQoJCglNdWx0aUNhbGxHdWFyZCYgb3BlcmF0b3I9KE11bHRpQ2FsbEd1YXJkJiYgZykKCXsKCQl0b2tlbiA9IGcudG9rZW47CgkJZnJlZSA9IGcuZnJlZTsKCQlnLnRva2VuID0gbnVsbHB0cjsKCX0KCQpwcml2YXRlOgoJTXVsdGlDYWxsR3VhcmQoTXVsdGlDYWxsVG9rZW4mIHRva2VuKSA6IHRva2VuKCZ0b2tlbiksIGZyZWUoZmFsc2UpIHt9CgoJTXVsdGlDYWxsVG9rZW4qIHRva2VuOwoJYm9vbCBmcmVlOwoJCglmcmllbmQgTXVsdGlDYWxsR3VhcmQgZ3VhcmQoTXVsdGlDYWxsVG9rZW4mKTsKfTsKCk11bHRpQ2FsbEd1YXJkIGd1YXJkKE11bHRpQ2FsbFRva2VuJiB0KQp7CglNdWx0aUNhbGxHdWFyZCBnKHQpOwoJcmV0dXJuIGc7Cn0KCk11bHRpQ2FsbFRva2VuIGZvb1Rva2VuOwpNdWx0aUNhbGxUb2tlbiBiYXJUb2tlbjsKCnZvaWQgYmFyKCk7Cgp2b2lkIGZvbygpCnsKCWlmKGF1dG8gZyA9IGd1YXJkKGZvb1Rva2VuKSkKCXsKCQljb3V0IDw8ICJmb28gY2FsbGVkXG4iOwoJCQoJCWJhcigpOwoJfQp9Cgp2b2lkIGJhcigpCnsKCWlmKGF1dG8gZyA9IGd1YXJkKGJhclRva2VuKSkKCXsKCQljb3V0IDw8ICJiYXIgY2FsbGVkXG4iOwoJCQoJCWZvbygpOwoJfQp9CgppbnQgbWFpbigpCnsKCWNvdXQgPDwgIj4+IGV4cGxpY2l0IGNhbGwgdG8gZm9vOlxuIjsKCQoJZm9vKCk7CgoJY291dCA8PCAiXG4+PiBleHBsaWNpdCBjYWxsIHRvIGJhclxuIjsKCgliYXIoKTsKCglyZXR1cm4gMDsKfQ==