Polymorphic function signature as template argument (using lambda)

I try to work hard for several hours, and I was not able to get this work to work.

I have a template spin-locked template:

template<typename T> class spinlock { // ... volatile T *shared_memory; }; 

I am trying to create something like this:

  // inside spinlock class template<typename F, typename... Ars> std::result_of(F(Args...)) exec(F fun, Args&&... args) { // locks the memory and then executes fun(args...) }; 

But I'm trying to use a polymorphic function so that I can do this:

 spinlock<int> spin; int a = spin.exec([]() { return 10; }); int b = spin.exec([](int x) { return x; }, 10); // argument here, passed as x // If the signature matches the given arguments to exec() plus // the shared variable, call it int c = spin.exec([](volatile int &shared) { return shared; }); // no extra arguments, shared becomes the // variable inside the spinlock class, I need to make // a function call that matches this as well // Same thing, matching the signature int d = spin.exec([](volatile int &shared, int x) { return shared + x; }, 10); // extra argument, passed as x... should match too // Here, there would be an error int d = spin.exec([](volatile int &shared, int x) { return shared + x; }); // since no extra argument was given 

Basically, I'm trying to make an exec function that takes F(Args...) or F(volatile T &, Args...) as an argument.

But I can not automate type detection. How could I do this?

+4
source share
1 answer

Firstly, this signature will not compile:

 // inside spinlock class template<typename F, typename... Ars> std::result_of(F(Args...)) exec(F fun, Args&&... args) { // locks the memory and then executes fun(args...) }; 

Return type must be

 typename std::result_of<F(Args...)>::type 

If your compiler implements N3436 , then this function will not participate in overload resolution, if fun(args...) not a valid expression, but this is not required in C ++ 11 and has not yet been implemented by many compilers. You will need to do your own SFINAE check to prevent result_of error message if fun(args...) invalid, or rewrite it without result_of

 template<typename F, typename... Args> auto exec(F fun, Args&&... args) -> decltype(fun(std::forward<Args>(args)...)) { // locks the memory and then executes fun(args...) } 

Then you can overload it for functions that require an additional parameter:

 template<typename F, typename... Args> auto exec(F fun, Args&&... args) -> decltype(fun(*this->shared_memory, std::forward<Args>(args)...)) { // locks the memory and then executes fun(*shared_memory, args...) } 

If fun(std::forward<Args>(args)...) invalid, the first overload will not participate in overload resolution. If fun(*this->shared_memory, std::forward<Args>(args)...) invalid, the second overload will not participate in overload resolution. If neither of them is valid, the call will be poorly formed; if both are valid, the call will be ambiguous.

+3
source

All Articles