i am new using c++11 features and also tryng to use SDL_Widget-2 lib for build a simple Gui for my project. But i am getting stuck in the problem :
#include "sdl-widgets.h"
class Builder
{
public:
Builder():top_win(nullptr)
,but(nullptr)
{
top_win=new TopWin("Hello",Rect(100,100,120,100),0,0,false,
[]() {
top_win->clear();
draw_title_ttf->draw_string(top_win->render,"Hello world!",Point(20,40));
}
);
but=new Button(top_win,0,Rect(5,10,60,0),"catch me",
[](Button *b) {
static int dy=60;
b->hide();
b->move(0,dy);
b->hidden=false;
dy= dy==60 ? -60 : 60;
});
}
private:
TopWin * top_win;
Button *but;
};
int main(int,char**) {
Builder aViewBuilder;
get_events();
return 0;
}
with the error in the compilation stage:
In lambda function:
error: 'this' was not captured for this lambda function
error: 'this' was not captured for this lambda function
this error is printed out twice int the console.
I have try :
[this](){}
[=](){}
and
[&](){}
with different compile error but a cannot go more further.
Can any see a fix?
You do need to capture with [this] or [&]. I suspect that the TopWin and Button constructors take raw function pointers, and need to take std::functions instead.
A plain vanilla function pointer is not compatible with capturing lambdas. std::function is able to work like a function pointer that also allows safe storage of captured data. (i.e. the captured objects will need to be properly copied or destroyed when the function object is itself copied or destroyed)
Related
I want to reliaze how to use boost::aio::async_connect with lambda.
Boost version 1.68
It's really strange that I could use std::bind but not lambda.
If I use std::bind, it work.
But when I use lambda, it buillt failed, and said "IteratorConnectHandler type requirements not met.
std::bind version (worked)
void SslClient::connect(boost::asio::ip::tcp::resolver::results_type results) {
auto sp = shared_from_this();
boost::asio::async_connect(ws->next_layer().next_layer(),
results.begin(),
results.end(),
std::bind(
on_connect,
std::placeholders::_1)
);
}
lambda version (not worked)
void SslClient::connect(boost::asio::ip::tcp::resolver::results_type results) {
auto sp = shared_from_this();
boost::asio::async_connect(ws->next_layer().next_layer(),
results.begin(),
results.end(),
[&, sp](boost::system::error_code ec) {
if (ec) {
return;
}
ws->next_layer().async_handshake(boost::asio::ssl::stream_base::client,
[&, sp](boost::system::error_code ec1) {
handShake(ec);
});
}
);
}
So how to use lambda here?
You call async_connect with pair of iterators, so your lambda should meet iterator connect handler requirements. As second parameter you have to pass connected endpoint.
boost::asio::async_connect(ws->next_layer().next_layer(),
results.begin(),
results.end(),
[&, sp]( boost::system::error_code ec,
boost::asio::ip::tcp::resolver::iterator it)
{
if (ec) {
return;
}
//...
To be consistent with reference you should also fix bind version. on_connect should also take iterator as second param.
Your current bind version compiles and works, but when asynchronous operation initiated by async_connect is completed, functor created by bind is called with only error_code, you cannot access endpoint. You can modify bind so that it takes on_connect without any arguments.
void on_connect(){}
boost::asio::async_connect(ws->next_layer().next_layer(),
results.begin(), results.end(), std::bind(on_connect)); // compiles fine
this also compiles, but when handler is called neither error_code nor endpoint can be accessed. (Yes it is a bit strange that you are not getting compiler errors when using bind which inform that requirements of handler are not fulfilled. I don't know where this disagreement between lambda and bind comes from.)
I want automatic deduction of the arguments of a templated function which accepts a function, while using lambdas. This Example shows some of my options:
template <class T>
void foo(void (*func)(T)) {
T val;
// do something with val and func...
}
int main() {
auto pfunc0 = [] (int) { /*...*/ };
void (*pfunc1)(int) = [] (int) { /*...*/ };
auto* pfunc2 = +[] (int) { /*...*/ };
foo(pfunc0); // not ok
foo<int>(pfunc0); // ok, but redundant
foo(pfunc1); // ok, but redundant
foo(pfunc2); // ok
}
pfunc2 uses a trick I learned here: Obtaining function pointer to lambda?. So actually I should be happy with the pfunc2 case as it is concise and non repeating code, unfortunately the Visual C++ 2012 IDE complains it was erroneous code even though it compiles just fine.
Are there any workarounds or recommendations for this problem?
IDE error messages:
In the "auto* pfunc2" line: The IDE underlines 'auto' and says
Error: cannot deduce 'auto' type
also it underlines '[' where it complains
Error: more than one conversion function from "lambda[]void (int)->void" to a build-in type applies:
function "lambda[]void (int)->void::operator void (*)(int)() const"
function "lambda[]void (int)->void::operator void (*)(int)() const"
function "lambda[]void (int)->void::operator void (*)(int)() const"
This is related to this bug (closed as "by design"). VC++ supports several calling conventions on x86 and lambdas with empty capture lists provide conversions to them all. That's why there's ambiguity.
Unfortunately, there's no workaround listed that you haven't already tried.
By the way, this bug is listed as fixed in Visual C++ 2015 Update 2
I have a simple task class:
template<typename TType>
class YHMTask
{
public:
YHMTask() {};
template<typename TLambdaFun>
auto then(TLambdaFun f) -> std::future<decltype(f(mTask.get()))>
{
std::move(mTask);
return std::async(std::launch::async, f, mTask.get());
}
std::future<TType> mTask;
private:
};
In this code, .then can be used and return a std::future.
But I want .then to return another YHMTask so that I can call .then after .then.
I tried to change .then code to follow:
template<typename TLambdaFun>
auto then(TLambdaFun f) -> YHMTask<decltype(f())>
{
std::move(mTask);
std::async(std::launch::async, f, mTask.get());
YHMTask<decltype(f())> yhmTask(std::move(this));
return yhmTask;
}
And call .then like this:
auto testTask = YHMCreateTask(PostAsync(L"", L"")).then([=](wstring str)
{
return 1;
});
Compilier give me this error:
error C2672: 'YHMTask<std::wstring>::then': no matching overloaded function found
error C2893: Failed to specialize function template 'YHMTask<unknown-type> YHMTask<std::wstring>::then(TLambdaFun)'
How should I do?
When you create yhmTask you are moving this, which is a pointer. There is no constructor for YHMTask that takes a pointer to a YHMTask so the template specialization fails. You should dereference this before moving it:
YHMTask<decltype(f())> yhmTask(std::move(*this));
Sounds like you are interested in extending std::future to have .then(). I recommend taking a look at Futures for C++ at Facebook. It does what your attempting to do and more.
Lets you chain a sequence tasks using then:
Future<double> fut =
fooFuture(input)
.then(futureA)
.then(futureB)
.then(futureC)
.then(d)
.then([](OutputD outputD) { // lambdas are ok too
return outputD * M_PI;
});
Also provides other compositional building blocks such as collect, map, and reduce. Git repo here. Looks like C++17 may also have support for the .then construct.
Lets consider following example:
#include <functional>
#include <iostream>
using namespace std;
class Caller {
public:
Caller(function<void()> callback) {
callback();
}
};
main() {
#if defined(ONELINER)
Caller caller = [] { cout << "test"; };
#else
function<void()> fun = [] { cout << "test"; };
Caller caller(fun);
#endif // defined(ONELINER)
}
If we simply try to compile it (with -std=c++11 flag) it will happily finish, and display test when run. However if we define ONELINER macro compilation will fail with:
prog.cpp: In function 'int main()':
prog.cpp:17:40: error: conversion from 'main()::<lambda()>' to non-scalar type 'Caller' requested
Caller caller = [] { cout << "test"; };
I understand that this is caused by the fact that there is implicit conversion from lambda to std::function and then implicit conversion from std::function to Caller, and we cannot perform 2 conversions at the same time.
Is it somehow possible to make syntax Class object = lambda; work? I'm asking because I played recently with writing my own small testing framework for educational reasons and I thought that this:
UNIT_TEST(test_name) {
// test content
};
is much more elegant than
UNIT_TEST_BEGIN(test_name)
// unit test
UNIT_TEST_END()
The former can be achieved with lambdas passed into the UnitTest constructor. But with problem that I described I had to use dirty workaround like:
#define UNIT_TEST(test_name) \
::std::function<void(::Helper*)> test_name_helper; \
::UnitTest test_name ## _test = \
test_name_helper = \
[&] (::Helper* helper)
and it doesn't look elegant at all. But even if this can be done without lambdas I'm still intrigued whether Class object = lamda; syntax can be achieved.
Modify the constructor as such:
template<typename CB>
Caller(CB callback) {
callback();
}
That will allow it to accept any callable argument, be it a lambda, a std::function, function pointer or functor.
Unfortunately the constructor will also accept any other type as well, but give a compiler error when callback can't be "called" like a function.
Sorry about the title, I couldn't come with a better one.
Suppose that I have a class with special delete semantics, which needs to call a function instead of been deleted by delete, let's call it releaseable_object:
struct releaseable_object
{
releaseable_object() : dummy_ptr(new int) {}
void Release()
{
std::cout << "Releasing releaseable object\n";
delete dummy_ptr;
}
int *const dummy_ptr;
};
And this releaseable_object is the base class of a bunch of other objects, each of them constructed by a factory which only returns pointers.
I'm trying to wrap each class into a std::unique_ptr with a custom deleter which call the releaseable_object::Release() function, so I've created a helper struct to handle some of the generic stuff:
// std::is_base_of<releaseable_object, T>::value must be true
template <typename T> struct Managed
{
using type = T;
static void deleter(type *object)
{
std::cout << "Release!\n";
object->Release();
};
using pointer = std::unique_ptr<T, decltype(deleter)>;
};
And then, a bunch of derived classes which does all the specific initializations and calls to te factory:
struct ManagedA : Managed<A>
{
using base = Managed<A>;
using base::pointer;
using base::deleter;
ManagedA(/* lots of parameters */) :
m_pointer(nullptr, deleter)
{
// do A specific stuff...
A *a = factory::CreateA(/* lots of parameters */);
// more A specific stuff...
// wrap the pointer:
m_pointer.reset(a);
}
pointer m_pointer;
};
If I try to compile the code above, it complains about the unique_ptr (demo here), I don't know what I'm doing wrong there, the error is about the instantiation of a tuple (the complete error log is in the ideone demo):
tuple: In instantiation of ‘struct std::_Head_base<1u, void(A*), false>’:
tuple:229:12: recursively required from ‘struct std::_Tuple_impl<1u, void(A*)>’
tuple:229:12: required from ‘struct std::_Tuple_impl<0u, A*, void(A*)>’
tuple:521:11: required from ‘class std::tuple<A*, void(A*)>’
bits/unique_ptr.h:127:57: required from ‘class std::unique_ptr<A, void(A*)>’
If I get rid of the m_pointer member then the compilation succeeds. I'm pretty lost with this, I'll be grateful of any hints about how to fix the compilation error.
Thanks for your attention.
The problem is that decltype(deleter) is a function type instead of a pointer-to-function type. Changing the pointer declaration to
using pointer = std::unique_ptr<T, decltype(deleter)*>; // or spell out void(*)(T*)
will fix it.
Be aware that a function object type is usually preferable to a function pointer type for a unique pointer deleter, since the function pointer must be stored in the object itself. i.e.,
sizeof(std::unique_ptr<foo*,void(*)(foo*)>) == sizeof(foo*) + sizeof(void(*)(foo*))
but most implementations will take advantage of the Empty Base Optimization if you use an empty deleter type:
struct deleter_type {
void operator () (foo*) {
// ...
}
};
sizeof(std::unique_ptr<foo*,deleter_type>) == sizeof(foo*)
Here's how your sample code would be written using a deleter type..