TestCase2 and TestCase3 can compile normally. However, in TestCase1 I get the following error:
E0312, Custom conversion from "lambda []void ()->void" to
"EventHandler" is not appropriate.
Why am I getting this error? I want to know how to solve it.
#include <functional>
#include <iostream>
class EventHandler
{
std::function<void()> _func;
public:
int id;
static int counter;
EventHandler() : id{ 0 } {}
EventHandler(const std::function<void()>& func) : _func{ func }
{
id = ++EventHandler::counter;
}
};
int EventHandler::counter = 0;
int main()
{
EventHandler TestCase1 = []() {};
EventHandler TestCase2([]() {});
EventHandler TestCase3 = static_cast<std::function<void()>>([]() {});
}
Why am I getting this error?
The lambda []() {} is not the same as std::function<void()>. That means
decltype([]() {}) != std::function<void()>
and it has to be implicitly or explicitly converted.
At the line
EventHandler TestCase1 = []() {};
copy initialization take place, where compiler first has to convert the lambda to a std::function<void()> and then a EventHandler object. Compiler can not do double implicit conventions.
Therefore, you need to be explicit here, like in TestCase3 for instance.
I want to know how to solve it.
One way is to provide a templated constructor (if you willing to)
#include <type_traits> // std::is_convertible_v
class EventHandler
{
std::function<void()> _func;
public:
template<typename Func> EventHandler(Func func)
: _func{ func }
{
static_assert(std::is_convertible_v<Func, decltype(_func)>
, "is not valid arg!");
// ....
}
// or in C++20 with <concepts> header
// template<typename Func> EventHandler(Func func)
// requires std::convertible_to<Func, decltype(_func)>
// : _func{ func }
// { ... }
};
Now you can
EventHandler TestCase1 = []() {}; // works
Demo
Case 1
Here we consider the statement:
EventHandler TestCase1 = []() {};//this is copy initialization
the above statement uses copy initialization.
And from copy initialization's documentation:
In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.
And as EventHandler can't be directly produced from the initializer lambda on the right hand side, the first case of TestCase1 isn't allowed in accordance wirh the above quoted statement.
Case 2
Here we consider the statement,
EventHandler TestCase2([]() {});//this is direct initialization
the above uses direct initialization and since there is an implicit conversion available(using the converting constructor), this time it is allowed according to the above quoted statement.
Related
I can compile the following code without any problem (using gcc 11.1.0):
#include <iostream>
template <typename Func>
class K {
Func f;
public:
K(Func _f): f{_f} {};
void do_thing(int x) {f(x);};
};
int main()
{
auto f = [](int x) {std::cout << x << std::endl;};
K kl{f};
kl.do_thing(5);
return 0;
}
however I would like to perform some check in the constructor of the class K (for instance some std::is_convertible_v inside some bool function), so I tried to modify the code to
#include <iostream>
template <typename Func>
class K {
Func f;
public:
K(Func _f) {
...
f = _f;};
void do_thing(int x) {f(x);};
};
int main()
{
auto f = [](int x) {std::cout << x << std::endl;};
K kl{f};
kl.do_thing(5);
return 0;
}
which however gives me some error message
error: use of deleted function ‘main()::<lambda(int)>::<lambda>()’
and then
note: a lambda closure type has a deleted default constructor
This confuses me a lot since I cannot understand how it is possible that the former piece of code could compile since the lambda function has not default constructor.
Question
How can I set my f inside the body of the constructor? (This is just a MWE and in my case the class is a bit more complex and the checks I mentioned before make sense.)
How can I initialize my f inside the body of the constructor?
You can't. f = _f; inside the constructor body is assignment but not initialization. So f will be default-initialized firstly, then enter the constructor body (to perform assignment).
You might use std::function instead; which could be default-initialized, then you can assign it in constructor body.
BTW: Since C++20 your code will compile fine even it might not work as you expected (depending on the ... part). For lambdas,
If no captures are specified, the closure type has a defaulted default constructor. Otherwise, it has no default constructor (this includes the case when there is a capture-default, even if it does not actually capture anything).
Is this what you are looking for?
It is the generic solution, not making any assumptions on the signature of Fn
#include <iostream>
#include <utility>
template <typename Fn>
class K
{
public:
explicit K(const Fn& fn) :
m_fn{ fn }
{
};
template<typename... args_t>
auto do_thing(args_t&&... args)
{
return m_fn(std::forward<args_t>(args)...);
}
private:
Fn m_fn;
};
int main()
{
auto f = [](int x) {std::cout << x << std::endl; };
K kl{ f };
kl.do_thing(5);
}
Given the non copyable Task class and sample code below
#include <functional>
#include <iostream>
#include <string>
class Task
{
public:
Task()
{
}
Task(const Task& other) = delete;
Task& operator=(const Task& other) = delete;
Task(Task&& other) = default;
Task& operator=(Task&& other) = default;
void operator()() const
{
std::cout << "Task !" << std::endl;
}
};
int main()
{
auto task = Task();
auto lambda = [task = std::move(task)]
{
task();
};
std::function<void()> test = std::move(lambda);
test();
}
If I declare the test variable with type auto instead of std::function, the program compiles and runs perfectly, otherwise it will refuse to compile with this error:
functional:1878:34: error: use of deleted function 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)'
__dest._M_access<_Functor*>() =
^
31:42: note: 'main()::<lambda()>::<lambda>(const main()::<lambda()>&)' is implicitly deleted because the default definition would be ill-formed:
31:42: error: use of deleted function 'Task::Task(const Task&)'
13:5: note: declared here
I really need to declare the type of test since it will be in the end a member of another class.
How do I do that ?
Am I right to suppose that std::function should be in some way declared mutable ?
You can use decltype(foo) as a type when you want to refer to the type of foo. So, you could do this:
decltype(lambda) test = std::move(lambda);
However, your stated goal is to use this as a class member. In that case you need something to "steal" the type from. Note that the compiler is under no obligation (as far as I know) to unify the types of two identical lambda expressions. This means that both the type and the lambda creation must be taken from the same lambda expression.
If you really want to do this with lambdas and you have access to C++14 (for deduced return types) then you could do something like:
auto make_task_runner(Task task) {
return [task = std::move(task)]() { task(); };
}
This gives us a function that we can use both to create the lambdas, and to steal the type (by using decltype() over an invocation of the function).
Then, in your class you could have:
class SomeClass {
// Type alias just to make things simpler.
using task_runner_t = decltype(make_task_runner(std::declval<Task>()));
task_runner_t task_runner;
}
You can then assign to this data member by using the make_task_runner function:
task_runner = make_task_runner(std::move(some_task));
However, at this point you've already lost the primary benefit of lambdas: the ability to create a new short-lived, unnamed function on-the-fly. Now we have a named function to create the lambda object and we've given the lambda type a name (task_runner_t), so what is even the point of using lambda to solve this problem anymore?
In this particular case, a custom functor (as in Paul's answer) makes a lot more sense.
... However, Task is already a functor so you already have exactly the type you need: Task! Just use that instead of inventing a wrapper for no apparent benefit.
One way to approach this is to forego the syntactic sugar that a lambda offers you and do it yourself with a functor instead, e.g.:
#include <functional>
#include <iostream>
#include <string>
class Task
{
public:
Task()
{
}
Task(const Task& other) = delete;
Task& operator=(const Task& other) = delete;
Task(Task&& other) = default;
Task& operator=(Task&& other) = default;
void operator()() const
{
std::cout << "Task !" << std::endl;
}
};
class pseudo_lambda
{
public:
pseudo_lambda (Task &&task) { m_task = std::move (task); } // <- capture
void operator()() const { m_task (); } // <- invoke
private:
Task m_task; // <- captured variable(s)
};
int main()
{
auto task = Task();
pseudo_lambda pl { std::move (task) };
pl ();
}
Live demo
I'd like to create a class where the client can store a lambda expression like []() -> void {} as a field of the class, but I can't figure out how to do so. One answer suggested using decltype, which I tried with no success. Here is a ideone source link. The below is the source and result:
#include <cstdio>
auto voidLambda = []()->void{};
class MyClass {
public:
decltype(voidLambda) t;
MyClass(decltype(voidLambda) t) {
this->t = t;
}
};
int main() {
MyClass([] {
printf("hi");
});
}
Result:
prog.cpp: In constructor 'MyClass::MyClass(<lambda()>)':
prog.cpp:3:79: error: no matching function for call to '<lambda()>::__lambda0()'
prog.cpp:2:20: note: candidates are: <lambda()>::<lambda>(const<lambda()>&)
prog.cpp:2:20: note: <lambda()>::<lambda>(<lambda()>&&)
prog.cpp:3:88: error: no match for 'operator=' in '((MyClass*)this)->MyClass::t = t'
prog.cpp: In function 'int main()':
prog.cpp:5:27: error: no matching function for call to 'MyClass::MyClass(main()::<lambda()>)'
prog.cpp:3:48: note: candidates are: MyClass::MyClass(<lambda()>)
prog.cpp:3:14: note: MyClass::MyClass(const MyClass&)
Does anyone know how to do this?
If you want a class member to be a lambda expression, consider using the std::function<> wrapper type (from the <functional> header), which can hold any callable function. For example:
std::function<int()> myFunction = [] { return 0; }
myFunction(); // Returns 0;
This way, you don't need to know the type of the lambda expression. You can just store a std::function<> of the appropriate function type, and the template system will handle all the types for you. More generally, any callable entity of the appropriate signature can be assigned to a std::function<>, even if the the actual type of that functor is anonymous (in the case of lambdas) or really complicated.
The type inside of the std::function template should be the function type corresponding to the function you'd like to store. So, for example, to store a function that takes in two ints and returns void, you'd make a std::function<void (int, int)>. For a function that takes no parameters and returns an int, you'd use std::function<int()>. In your case, since you want a function that takes no parameters and returns void, you'd want something like this:
class MyClass {
public:
std::function<void()> function;
MyClass(std::function<void()> f) : function(f) {
// Handled in initializer list
}
};
int main() {
MyClass([] {
printf("hi")
}) mc; // Should be just fine.
}
Hope this helps!
The only way I can think of to store a lambda in a class is to use a template with a helper make_ function:
#include <cstdio>
#include <utility>
template<class Lambda>
class MyClass {
Lambda _t;
public:
MyClass(Lambda &&t) : _t(std::forward<Lambda>(t)) {
_t();
}
};
template<class Lambda>
MyClass<Lambda> make_myclass(Lambda &&t) {
return { std::forward<Lambda>(t) };
}
int main() {
make_myclass([] {
printf("hi");
});
}
In case of [] (empty capture) simple function pointer can be used. Declaration syntax is ReturnType (*pointer_name) (Arg1T, Arg2T); for pointer, ReturnType (&ref_name) (/*void*/); for reference (can't be null). Lambda with empty capture block is implicitly convertible to function pointer with same signature. And std::function have runtime and size (it is at least three times larger) overhead.
struct S
{
void (*f_p)() {}; // `{}` means `= nullptr`;
};
int main()
{
S s { [] { std::cout << "Lambda called\n"; }};
s.f_p();
S s2;
if (s2.f_p) // check for null
s.f_p();
s2.f_p = [] { std::cout << "Lambda2 called\n"; };
s2.f_p();
s2.f_p = std::terminate; // you can use regular functions too
s2.f_p();
}
Output
Lambda called
Lambda2 called
terminate called without an active exception
Lets say you have a variadic class with a std::tuple, that can be move constructed with args + 1 new arg. When constructed using std::apply() and a raw curly brace constructor, that constructor doesn't return an rvalue. Which means the class isn't move constructed. An example follows to clarify.
#include <cstdio>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <vector>
template <class... Args>
struct icecream {
icecream() = default;
template <class... MoreArgs>
icecream(icecream<MoreArgs...>&& ice) {
std::apply(
[this](auto&&... ds) {
data = { std::move(ds)..., {} };
},
std::move(ice.data));
}
// This works :
// template <class... MoreArgs>
// icecream(icecream<MoreArgs...>&& ice) {
// std::apply(
// [this](auto&&... ds) {
// data = { std::move(ds)...,
// std::move(std::vector<double>{}) };
// },
// std::move(ice.data));
// }
std::tuple<std::vector<Args>...> data{};
};
int main(int, char**) {
icecream<int> miam;
std::get<0>(miam.data).push_back(1);
std::get<0>(miam.data).push_back(2);
icecream<int, double> cherry_garcia{ std::move(miam) };
printf("miam : \n");
for (const auto& x : std::get<0>(miam.data)) {
printf("%d\n", x);
}
printf("\ncherry_garcia : \n");
for (const auto& x : std::get<0>(cherry_garcia.data)) {
printf("%d\n", x);
}
return 0;
}
The output is :
miam :
1
2
cherry_garcia :
1
2
The example is a little dumbed down, but illustrates the point. In the first move constructor, {} is used and the tuple copy constructs. If you uncomment the second constructor with a hardcoded std::move(), then it works.
I test on VS latest, clang latest and gcc latest. All have the same result. (wandbox : https://wandbox.org/permlink/IQqqlLcmeyOzsJHC )
So the question is, why not return an rvalue? I'm obviously missing something with the curly constructor. This might have nothing to do with the variadic stuff, but I thought I might as well show the real scenario.
Why doesn't raw curly constructor {} return an rvalue?
The problem is another.
The problem is that
data = { std::move(ds)..., {} };
call the "direct constructor" (constructor (2) in this page),
constexpr tuple( const Types&... args ); (2)
not the "converting constructor" (constructor (3))
template< class... UTypes >
constexpr tuple( UTypes&&... args ); (3)
that you expect.
The problem is that "{}" isn't enough, for the compiler, to deduce a type (the last type for UTypes... list in constructor (3)) so the constructor (3) is excluded and the compiler choose the constructor (2).
Whit constructor (2), "{}" is acceptable to construct an object of the last type of the Types... of the list because the Types... is know and not to be deduced.
But constructor (2) is a copy constructor (from the point of view of the Types... of the tuple), not a forward constructor as constructor (3), so the first vector is copied, not moved.
It's different when you call
data = { std::move(ds)..., std::move(std::vector<double>{}) };
or also
data = { std::move(ds)..., std::vector<double>{} };
because the last argument can be clearly deduced as std::vector<double>{} && so the compiler call the "converting constructor" (constructor (3)) and move the content of the first vector.
Off Topic: instead of using std::vector<double>{}, that works only when double is the last of the types in Args..., I suggest to write a more generic code using std::tuple_element.
Moreover, I suggest to SFINAE enable your constructor only when sizeof...(MoreArgs)+1u == sizeof...(Args).
Maybe also std::forward() (enabling perfect forwarding) instead of std::move() inside the lambda.
So I suggest the following constructor
template <typename ... MoreArgs,
std::enable_if_t<sizeof...(MoreArgs)+1u == sizeof...(Args)> * = nullptr>
icecream(icecream<MoreArgs...>&& ice) {
std::apply(
[this](auto && ... ds) {
data = { std::forward<decltype(ds)>(ds)...,
std::tuple_element_t<sizeof...(Args)-1u,
decltype(data)>{} };
},
std::move(ice.data));
}
I want to pass an rvalue through std::bind to a function that takes an rvalue reference in C++0x. I can't figure out how to do it. For example:
#include <utility>
#include <functional>
template<class Type>
void foo(Type &&value)
{
Type new_object = std::forward<Type>(value); // move-construct if possible
}
class Movable
{
public:
Movable(Movable &&) = default;
Movable &operator=(Movable &&) = default;
};
int main()
{
auto f = std::bind(foo<Movable>, Movable());
f(); // error, but want the same effect as foo(Movable())
}
The reason this fails is because when you specify foo<Movable>, the function you're binding to is:
void foo(Movable&&) // *must* be an rvalue
{
}
However, the value passed by std::bind will not be an rvalue, but an lvalue (stored as a member somewhere in the resulting bind functor). That, is the generated functor is akin to:
struct your_bind
{
your_bind(Movable arg0) :
arg0(arg0)
{}
void operator()()
{
foo<int>(arg0); // lvalue!
}
Movable arg0;
};
Constructed as your_bind(Movable()). So you can see this fails because Movable&& cannot bind to Movable.†
A simple solution might be this instead:
auto f = std::bind(foo<Movable&>, Movable());
Because now the function you're calling is:
void foo(Movable& /* conceptually, this was Movable& &&
and collapsed to Movable& */)
{
}
And the call works fine (and, of course, you could make that foo<const Movable&> if desired). But an interesting question is if we can get your original bind to work, and we can via:
auto f = std::bind(foo<Movable>,
std::bind(static_cast<Movable&&(&)(Movable&)>(std::move<Movable&>),
Movable()));
That is, we just std::move the argument before we make the call, so it can bind. But yikes, that's ugly. The cast is required because std::move is an overloaded function, so we have to specify which overload we want by casting to the desired type, eliminating the other options.
It actually wouldn't be so bad if std::move wasn't overloaded, as if we had something like:
Movable&& my_special_move(Movable& x)
{
return std::move(x);
}
auto f = std::bind(foo<Movable>, std::bind(my_special_move, Movable()));
Which is much simpler. But unless you have such a function laying around, I think it's clear you probably just want to specify a more explicit template argument.
† This is different than calling the function without an explicit template argument, because explicitly specifying it removes the possibility for it to be deduced. (T&&, where T is a template parameter, can be deduced to anything, if you let it be.)
You could use a lambda expression.
auto f = [](){ foo(Movable()); };
This would seem to be the simplest option.
Guys i have hacked up a perfect forwarding version of a binder(limited to 1 param) here
http://code-slim-jim.blogspot.jp/2012/11/stdbind-not-compatable-with-stdmove.html
For reference the code is
template <typename P>
class MovableBinder1
{
typedef void (*F)(P&&);
private:
F func_;
P p0_;
public:
MovableBinder1(F func, P&& p) :
func_(func),
p0_(std::forward<P>(p))
{
std::cout << "Moved" << p0_ << "\n";
}
MovableBinder1(F func, P& p) :
func_(func),
p0_(p)
{
std::cout << "Copied" << p0_ << "\n";
}
~MovableBinder1()
{
std::cout << "~MovableBinder1\n";
}
void operator()()
{
(*func_)(std::forward<P>(p0_));
}
};
As u can see from the above proof of concept, its very possible...
I see no reason why std::bind is incompatible with std::move... std::forward is after all for perfect forwarding I dont understand why there isnt a std::forwarding_bind ???
(This is actually a comment to GMan's answer, but I need some formatting for the code).
If generated functor actually is like this:
struct your_bind
{
your_bind(Movable arg0) :
arg0(arg0)
{}
void operator()()
{
foo(arg0);
}
Movable arg0;
};
then
int main()
{
auto f = your_bind(Movable());
f(); // No errors!
}
compliles without errors. as it's possible to assign and initialize data with rvalue and then pass a data value to rvalue argument of the foo(). However, I suppose that bind implementation extracts function argument type directly from foo() signature. i.e. the generated functor is:
struct your_bind
{
your_bind(Movable && arg0) :
arg0(arg0) // **** Error:cannot convert from Movable to Movable &&
{}
void operator()()
{
foo(arg0);
}
Movable&& arg0;
};
and indeed, this really fails to initialize rvalue data member.
Perhaps,the bind implpementation simply does not correctly extract "unreferenced" type from function argument type and uses this type for functor's data member declaration "as is", without trimming &&.
the correct functor should be:
struct your_bind
{
your_bind(Movable&& arg0) :
arg0(arg0)
{}
void operator()()
{
foo(arg0);
}
Movable arg0; // trim && !!!
};
One more improvement in GManNickG's answer and I've got pretty solution:
auto f = std::bind(
foo<Movable>,
std::bind(std::move<Movable&>, Movable())
);
(works in gcc-4.9.2 and msvc2013)