I am still struggling with some C++ syntax.
This time I want to add extra arguments with the lambda. But to make the code generic I ant to be able to accept any function and its arguments:
#include <functional>
#include <exception>
template<typename R>
class Nisse
{
private:
Nisse(Nisse const&) = delete;
Nisse(Nisse&&) = delete;
Nisse& operator=(Nisse const&) = delete;
Nisse& operator=(Nisse&&) = delete;
public:
//Nisse(std::function<R()> const& func) {} // disable for testing
template<typename... Args>
Nisse(std::function<R(Args...)> const& func, Args... a) {}
};
int main()
{
// I was hoping this would deduce the template arguments.
Nisse<int> nisse([](int a,double d){return 5;},12,12.0);
}
This generates:
> g++ -std=c++0x Test.cpp
Test.cpp:21:61: error: no matching function for call to ‘Nisse<int>::Nisse(main()::<lambda(int, double)>, int, double)’
Test.cpp:21:61: note: candidate is:
Test.cpp:16:9: note: template<class ... Args> Nisse::Nisse(const std::function<R(Args ...)>&, Args ...)
I tried explicitly specifying the template types:
Nisse<int> nisse<int,double>([](int a,double d){return 5;},12,12.0);
But this (surprising to me) is a syntax error:
> g++ -std=c++0x Test.cpp
Test.cpp: In function ‘int main()’:
Test.cpp:21:23: error: expected initializer before ‘<’ token
Test.cpp:21:65: error: expected primary-expression before ‘,’ token
Test.cpp:21:73: error: expected ‘;’ before ‘)’ token
You can’t infer
std::functiontemplate arguments from a lambda. The usual way to accept arbitrary callables is by universal reference:The final (anonymous, defaulted) template argument is used here to validate that the first template argument is function like and returns a result of type R.
As described in the comments below by @Yakk The above expression checks that F is a function type whose result is R. If it works then all is fine. If it fails then it generates a compile time error (NOTE: this uses SFINAE).
For methods, SFINAE is inserted into the return type, but for constructors this isn’t an option; historically an extra, default constructor argument was added but adding a defaulted template argument is more elegant as it doesn’t change the constructor signature at all. SFINAE by anonymous template parameter is particularly attractive following variadic template parameters as there’s no way for the user to (accidentally?) override the default.