lambda不等于std::function,传参时会发生隐式转换 https://cplusplus.com/forum/general/272010/
原帖节选,
The compiler writes a new class for each lambda expression that appears in the code - therefore, the type of count is not std::function<void(void)>. Instead, its type is unique - a compiler-generated class type that we’ll call ClosureType.
When you pass count to invokeV1 (by-value), you’ve provided an argument with type ClosureType where a std::function<void(void)> was expected, so a conversion is required.
In order to do so, the compiler implicitly instantiates and calls std::function<void(void)>’s constructor template, which has the signature
template<typename F> function(F f);
The constructor that’s finally called
a.) is non-explicit; and
b.) has one argument.
Such constructors are called converting constructors. Converting constructors are the only constructors suitable for use by the compiler during implicit conversions.
The constructor produces a std::function<void(void)> that wraps a copy of the function object count. The result is used to initialize the parameter fn. When fn’s finally called, it doesn’t affect the original object at all. Note that the copy of count is made by std::function’s constructor during the implicit conversion, not by your code.
When you pass count to invokeV2 (by-reference), the situation’s the same as the last paragraph.
If you declared count as
std::function<void(void)> count{ [i]() mutable {
std::cout << ++i << '\n';
} };then no conversion step is required - so no copy is made unless you pass by value. If you pass count by reference, the changes to the state of count will be reflected throughout the program.
#include <iostream>
#include <functional>
using fn_type = std::function<void(void)>;
void call_std_fn_passed_by_const_reference (fn_type const& fn)
{ std::cout << "std::function const&: "; fn(); }
void call_std_fn_passed_by_mutable_reference(fn_type& fn)
{ std::cout << "std::function&: "; fn(); }
void call_std_fn_passed_by_value (fn_type fn)
{ std::cout << "std::function: "; fn(); }
template <typename Fn> void call_fn_by_value(Fn fn)
{ std::cout << "F: "; fn(); }
int main()
{
{
fn_type fn { [i=0]() mutable { std::cout << (++i) << '\n'; } };
call_std_fn_passed_by_const_reference(fn);
call_std_fn_passed_by_mutable_reference(fn);
call_std_fn_passed_by_value(fn);
call_fn_by_value(fn);
std::cout << '\n';
}
{
auto fn { [i=0]() mutable { std::cout << (++i) << '\n'; } };
call_std_fn_passed_by_const_reference(fn);
// error: result of conversion is not an lvalue
// call_std_fn_passed_by_mutable_reference(fn);
call_std_fn_passed_by_value(fn);
call_fn_by_value(fn);
std::cout << '\n';
}
{
fn_type fn { [i=0]() mutable { std::cout << (++i) << '\n'; } };
call_std_fn_passed_by_const_reference(std::ref(fn));
call_std_fn_passed_by_mutable_reference(std::ref(fn));
call_std_fn_passed_by_value(std::ref(fn));
call_fn_by_value(std::ref(fn));
std::cout << '\n';
}
{
auto fn { [i=0]() mutable { std::cout << (++i) << '\n'; } };
call_std_fn_passed_by_const_reference(std::ref(fn));
// error: not an lvalue
// call_std_fn_passed_by_mutable_reference(std::ref(fn));
call_std_fn_passed_by_value(std::ref(fn));
call_fn_by_value(std::ref(fn));
std::cout << '\n';
}
}
// outputs:
g++ -std=c++17 -O2 -Wall -Wextra -pedantic-errors -fsanitize=undefined main.cpp && ./a.out
std::function const&: 1
std::function&: 2
std::function: 3
F: 3
std::function const&: 1
std::function: 1
F: 1
std::function const&: 1
std::function&: 2
std::function: 3
F: 3
std::function const&: 1
std::function: 2
F: 3