How I can pass lambda expression to c++ template as parameter
A lambda is not a function pointer! A lambda is an instance of compiler generated class!
However, a non capturing lambda may be converted to a function pointer using it's operator+
Here's an example:
int main() {
auto lambda = [](int a) { return a; };
func ptr = +lambda; // this would work
return 0;
}
Sadly, the operator+
won't even work in your case because it has not been declared as constexpr, so you can't use it in a template parameter.
A fix to your case would be to use a free function... until N4487 is not accepted, you can't expect to pass lambda as template parameter.
Another fix would be to create your own functor instead of a lambda:
struct LambdaType {
constexpr LambdaType() = default;
int operator()(int a) {
return run(a);
}
// this is a non-capturing lambda, the operator can be
// in a static function
static int run(int a) {
return a;
}
};
int main() {
LambdaType lambda;
function<&LambdaType::run>(1); // ---> this is working
return 0;
}
This solution is not quite appealing, but it might be useful if LambdaType
is hidden in a cpp file.
If your goal is only the compiler to be able to inline your code, you can use templates to pass the lambda around:
#include <iostream>
template <typename T>
int function(T foo, int a) {
return foo(a);
}
int main() {
int a;
std::cin >> a;
int b = function([](int a) { return a; }, a);
return b;
}
Since the compiler knows the type of T
for each instanciation, a good compiler should be able to optimize out the lambda.
With clang, the third option gives the following assembly:
main: # @main
pushq %rax
leaq 4(%rsp), %rsi
movl std::cin, %edi
callq std::basic_istream<char, std::char_traits<char> >::operator>>(int&)
movl 4(%rsp), %eax # this is the call to the function
addq $8, %rsp
retq
pushq %rax
movl std::__ioinit, %edi
callq std::ios_base::Init::Init()
movl std::ios_base::Init::~Init(), %edi
movl std::__ioinit, %esi
movl $__dso_handle, %edx
popq %rax
jmp __cxa_atexit # TAILCALL
I used -std=c++14 -Ofast -march=native
as flags.
Passing a lambda into a function template
Your function binsearch
takes a function pointer as argument. A lambda and a function pointer are different types: a lambda may be considered as an instance of a struct implementing operator()
.
Note that stateless lambdas (lambdas that don't capture any variable) are implicitly convertible to function pointer. Here the implicit conversion doesn't work because of template substitution:
#include <iostream>
template <typename T>
void call_predicate(const T& v, void (*predicate)(T)) {
std::cout << "template" << std::endl;
predicate(v);
}
void call_predicate(const int& v, void (*predicate)(int)) {
std::cout << "overload" << std::endl;
predicate(v);
}
void foo(double v) {
std::cout << v << std::endl;
}
int main() {
// compiles and calls template function
call_predicate(42.0, foo);
// compiles and calls overload with implicit conversion
call_predicate(42, [](int v){std::cout << v << std::endl;});
// doesn't compile because template substitution fails
//call_predicate(42.0, [](double v){std::cout << v << std::endl;});
// compiles and calls template function through explicit instantiation
call_predicate<double>(42.0, [](double v){std::cout << v << std::endl;});
}
You should make your function binsearch
more generic, something like:
template <typename T, typename Predicate>
T binsearch(const std::vector<T> &ts, Predicate p) {
// usage
for(auto& t : ts)
{
if(p(t)) return t;
}
// default value if p always returned false
return T{};
}
Take inspiration from standard algorithms library.
C++ Pass lambda to template parameter
Lambdas in C++14, including their conversion to function pointers, are not constexpr.
In C++17, this is going to change. There are no stable compilers with that feature implemented that I'm aware of (if you find one, can you mention it in the comments below?).
At that point
constexpr auto tmp = []() -> void { std::cout << "Hello world\n"; };
function<+tmp>();
will definitely work. I am uncertain if
function<+[]() -> void { std::cout << "Hello world\n"; }>()
would work; there are some rules about lambdas in unevaluated contexts and inside template argument lists that may be separate from the constexpr
lambda problem and may apply here.
We can hack it in C++14.
Create a template class that stores a static copy of a lambda and exposes a static function with the same signature (f_ptr
) that calls that static copy of a lambda.
Instantiate it once globally with your lambda.
Pass a pointer to the f_ptr
to your template.
So:
template<class L> struct stateless; // todo
template<class L> stateless<L> make_stateless(L l){return std::move(l);}
auto foo = make_stateless( []() -> void { std::cout << "Hello world\n"; } );
function< &foo::f_ptr >();
this is almost certainly not what you want.
Pass C++20 Templated Lambda to Function Then Call it
The issue is that lambdas are not class templates, they're just regular classes where the member call operator, i.e. operator()
is templated.
When the template parameters are deduced for a generic lambda, this distinction is not noticeable (which is a very good thing).
So in your example, lambda
is not a class template, but you are using syntax that would be used for a class, not a member function.
If you want to specify the template parameters for a lambda explicitly, you'll need to say that you're calling the member operator()
of lambda
, and you'll need to say that it's a template to disambiguate.
lambda.template operator()<Alignment::eight>(t.data(), t.size());
Here's the version of your code that compiles.
Passing Type Into Lambda Function In C++ Template
The problem is the rigidity of CLang
compilers with respect to the standard.
The problem is not the type(that is correct), the problem is that you have to put typename before template dependant types.
However the best solution is to use auto to let the compiler deduce the type itself.
Passing a lambda function to a template method
The function call tries to deduce T
from both the first and second function parameter.
It will correctly deduce T
from the first parameter, but fail to deduce it from the second parameter, because the second function argument is a lambda type, not a std::function
type.
If deduction isn't possible from all parameters that are deduced context, deduction fails.
You don't really need deduction from the second parameter/argument here, since T
should be fully determined by the first argument. So you can make the second parameter a non-deduced context, for example by using std::type_identity
:
void eraserFunction(std::vector<T>& array, std::type_identity_t<std::function<int(const T&, const T&)>> func)
This requires C++20, but can be implemented easily in user code as well if you are limited to C++11:
template<typename T>
struct type_identity { using type = T; };
and then
void eraserFunction(std::vector<T>& array, typename type_identity<std::function<int(const T&, const T&)>>::type func)
std::identity_type_t<T>
is a type alias for std::identity_type<T>::type
. Everything left to the scope resolution operator ::
is a non-deduced context, which is why that works.
If you don't have any particular reason to use std::function
here, you can also just take any callable type as second template argument:
template<class T, class F>
void eraserFunction(std::vector<T>& array, F func)
This can be called with a lambda, function pointer, std::function
, etc. as argument. If the argument is not callable with the expected types, it will cause an error on instantiation of the function body containing the call. You can use SFINAE or since C++20 a type constraint to enforce this already at overload resolution time.
How to pass lambda expression as parameters in C++
A lambda is a different type than std::function
. You can add another template parameter to allow passing anything callable (which lambdas are) as the comparator function.
template <typename T, typename Predicate>
int count_if(typename linkList<T>::iterator it_start, typename linkList<T>::iterator it_end, Predicate&& cmp ){
int ret = 0;
while(it_start != it_end){
if(cmp(*it_start)) ++ret;
++it_start;
}
return ret;
}
How to pass a lambda to a template paramater
In C++11? With a lambda as template parameter?
Given that a lambda (before C++20) can't be used in an unevaluated context (so in a decltype()
) and can't be default constructed, I don't see a way.
The best I can imagine, in C++11, to reproduce something similar is something as follows
template <typename T, typename F = std::function<std::string(T const &)>>
std::string func (T const & t, F f = [](const T &t){return std::string{t};})
{ return f(t); }
that you can call with only the first argument
func("abc");
given that you accept the default lambda (but is saved as a std::function
).
You can also pass another lambda, if you don't like the default one
func(1, [](int const &){ return "one"; });
but as a traditional argument, not as template parameter.
C++ lambda as std::function in template function
What about simply as follows ?
template <typename F>
auto Context::executeTransient (F const & commands) {
...
auto result = commands(commandBuffer);
...
return result;
}
This way your method accept both standard functions and lambdas (without converting them to standard functions, that is preferable, from the performance point of view (as far as I know)) and the return type is deduced from the use (auto
).
In you need to know the R
type inside the method, you can apply decltype()
to result
auto result = commands(commandBuffer);
using R = decltype(result);
If you need to know the R
type as template parameter of the method, its a little more complex because involve std::declval()
and, unfortunately, add redundancy
template <typename F,
typename R = decltype(std::declval<F const &>()(commandBuffer))>
R Context::executeTransient (F const & commands) {
...
R result = commands(commandBuffer);
...
return result;
}
Related Topics
Cmake: Project Structure with Unit Tests
Is There a C++ Gdb Gui for Linux
How Exactly Is Std::String_View Faster Than Const Std::String&
Abstract Class VS Interface in C++
C++11 Std::Threads VS Posix Threads
Array of Pointers as Function Parameter
Recursion in C++ Factorial Program
How to Enforce the 'Override' Keyword
Multiple Sfinae Class Template Specialisations Using Void_T
Why Must Virtual Base Classes Be Constructed by the Most Derived Class
When a Float Variable Goes Out of the Float Limits, What Happens
Can Void* Be Used to Store Function Pointers
Glut Deprecation in MAC Osx 10.9, Ide: Qt Creator
Why Do Lambda Functions Drop Deduced Return Type Reference by Default