ARMmbed / mbed-os

Arm Mbed OS is a platform operating system designed for the internet of things
https://mbed.com
Other
4.66k stars 2.97k forks source link

Align C++ version with compiler supported. #5507

Closed pan- closed 5 years ago

pan- commented 6 years ago

Description


Enhancement

Reason to enhance or problem with existing solution

Mbed OS 5.8 will be a leap forward in compiler supports. ARM compiler v5.06 will be deprecated in favor of v6.7and IAR v7.8 will be deprecated in favor of IAR v8.2. For both of these compilers the major version change induce a change in the version of C++ they support:

mbed os 5.6

C++98 C++11 C++14
GCC 6 X X X
ARM 5.06 X ~ partial -
IAR 7.80 X - -

mbed-os 5.8

C++98 C++11 C++14
GCC 6 X X X
ARMC 6.7 X X beta
IAR 8.2 - - X

The choice of C++98 as the C++ standard supported by mbed was obvious for mbed OS 5.6 but it is not for mbed OS 5.8 because IAR v8.2 only compile in C++ 14 mode and does not provide backward compatibility mode.

As close as they are C++98, C++11 and C++14 standards are not 100% backward compatible. As a consequence an mbed os 5.8 application may compile on one compiler and not the other or act slightly differently. The introduction of new keywords may also breaks existing applications.

Suggested enhancement

There is no lowest common denominator between the compiler that mbed OS 5.8 will support. However C++14 is much closer to C++11 than C++98. I'd suggest to define C++11 as the mode used by C++ compilers when they compile an mbed application and use C++14 when the ARM compiler supports it officially (in beta actually).

From my perspective it doesn't mean that our codebase should allow new features of the standards mentioned above. I believe this question should be addressed in a different thread; we can use the CI to ensure that our code base follows our actual guideline.

Notes:

Breaking changes introduced by C++11 can be found in the Section C2 of the C++11 specification and breaking changes introduced by C++14 can be found in the section C3 of the C++14 specification.

pan- commented 6 years ago

@sg- @theotherjimmy @deepikabhavnani @bulislaw [Mirrored to Jira]

bulislaw commented 6 years ago

We won't be changing compilers version in 5.7, it's pushed to 5.8. [Mirrored to Jira]

pan- commented 6 years ago

I've updated the issue; the question remains interresting. [Mirrored to Jira]

amq commented 6 years ago

From my perspective it doesn't mean that our codebase should allow new features of the standards

Which features are you afraid of the most and why? The question is genuine and I may use your answer for my projects. I promise not to elaborate further to avoid an infinite discussion loop :) [Mirrored to Jira]

theotherjimmy commented 6 years ago

@amq The way I read that did not indicate that we are afraid of new features, just that we should avoid them for now until we stabilize on a particular version. [Mirrored to Jira]

pan- commented 6 years ago

@amq Usage of new C++ features accross mbed OS codebase is a different topic. I sent you a private message on developper.mbed.org which may answer your question.

[Mirrored to Jira]

woodsking2 commented 6 years ago

5.8 has been released. It still work at c++98. Is it pushed to 5.9? [Mirrored to Jira]

woodsking2 commented 6 years ago

@bulislaw @pan- @amq @theotherjimmy [Mirrored to Jira]

0xc0170 commented 6 years ago

@woodsking2 What is the question? C++1x support? IAR8 update is still on the feature branch and needs more work, same for ARMC6. [Mirrored to Jira]

woodsking2 commented 6 years ago

@0xc0170 Is any play to make mbed os work at c++ 14? [Mirrored to Jira]

amq commented 6 years ago

@woodsking2 use a custom profile with -std=gnu++14 or modify the existing ones at tools/profiles/. [Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

One additional motivator to enable C++11 (or higher) not just in user projects, but also within Mbed OS itself: to replace mbed::Callback with std::function. mbed::Callback limits the number of parameters, and does not play nicely with lambda functions. Details in my comment on #4872. [Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

According to the table in the OP, C++14 is a (partially-supported?) "community feature" in ARMC 6.7. However, according to this page, ARM Compiler 6 "fully supports the C++14 language standard."

Is the table wrong? EDIT: If so, then there are no remaining blockers preventing the team from implementing C++14 support in Mbed OS, right? [Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

I'll echo @woodsking2's question. 5.8 has been released; what is the plan for this issue? [Mirrored to Jira]

theotherjimmy commented 6 years ago

Is the table wrong?

Yes. I corrected the table. [Mirrored to Jira]

pan- commented 6 years ago

@theotherjimmy The table wasn't wrong the page linked by @bmcdonnell-ionx was. If you look at the user guide v6.7 It is clearly indicated that C++14 is a community feature. C++14 entered beta with v6.8 and still is with v6.10.

@bmcdonnell-ionx Unlike std::function, mbed::callback does not use dynamic memory to store its inner function like object. This is by design to avoid invisible memory fragmentation and possible memory allocations in interrupt context. Of course it limits the number of parameters that a lambda can capture.

Presumably the lambda captures get translated to function parameters. I'm not sure where the extras come from.

No lambda capture is not related to the function parameters. A lambda is an anonymous function like object; captured variables are member of the object and a call operator is generated; it contains the body of the lambda and as the same parameters as the lambda:

int foo = 42;

auto bar = [foo](int a , int b) -> int { 
   return (a + b) * foo;
};

// bar is equivalent to baz: 

struct Baz { 
   Baz(int foo) : foo(foo) { }
   int operator()(int a, int b) { 
       return (a + b) * foo;
   } 
private:
   int foo;   
};

Baz baz(foo);

As you can see every capture increases the size of the lambda; at some point std::function rely on dynamic memory to save the function like object while mbed::callback throw a compile time error.

The template copy-pasta in mbed::Callback also impedes understanding from reading the code.

If C++11 is enabled then mbed::callback will have to be updated to remove the multiple workarounds present in the code (it's not just about variadic templates!); as a side effect it will lift the limitation on the number of parameters accepted by mbed::callback and it will be possible to provide better compile time error messages. I suppose documentation will also require an update explaining clearly limitations and how to deal with them.

[Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

@theotherjimmy / @pan-

The table wasn't wrong the page linked by @bmcdonnell-ionx was.

I guess you should revert the change to the table in the OP, then.

@pan-

C++14 is a community feature [in ARM Compiler]. C++14 entered beta with v6.8 and still is with v6.10.

What then is the plan for Mbed OS? Wait until ARM Compiler's C++14 is out of beta? Is there an ETA on that?

Could you instead work with both C++11 and C++14? Aim for using the subset of features supported by both, and use #defines to check the C++ version in the hopefully few places where C++14 breaks backward compatibility with C++11. [Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

@pan-, thanks for the corrections and elaboration.

Unlike std::function, mbed::callback does not use dynamic memory to store its inner function like object. This is by design to avoid invisible memory fragmentation and possible memory allocations in interrupt context.

I didn't know this, and I definitely wanted to!

EDIT: I finally figured out how to make an mbed::Callback out of a lambda.

auto myLambdaFunc = []{};

auto mbedCallback = callback(&myLambdaFunc, &decltype(myLambdaFunc)::operator());

If C++11 is enabled then mbed::callback will have to be updated to remove the multiple workarounds present in the code (it's not just about variadic templates!); as a side effect it will lift the limitation on the number of parameters accepted by mbed::callback and it will be possible to provide better compile time error messages.

~Yes please!~

~This is what I should've asked for, since std::function uses dynamic allocation.~

EDIT: I think this will aid in understanding. [Mirrored to Jira]

pan- commented 6 years ago

@bmcdonnell-ionx std::function (may) use a trick named small buffer optimization to avoid unnecessary memory allocations. Basically each std::function object includes a small buffer that can be use for inplace allocation: If the function like object in input fit into the buffer then the function like object is copied in place otherwise, it is constructed with dynamically allocated memory and the buffer is used to store information like the pointer to the function like object.

In mbed::callback this buffer is really small, basically it is large enough to hold a pointer and a pointer to function member. If the function like object in input is too large then a static assertion is raised.

To use lambda in Callback, there's no need to use the helper mbed::callback; just use the constructor:

mbed::Callback<void()> foo([] { } )

void expect_cb(const mbed::Callback<int(int, int)>& cb);

expect_cb([](int a , int b) -> int {
    // do something!
});

However I noticed two issues:

char large[256];

mbed::Callback<void()> qux(std::function<void()>([large](){

}));

[Mirrored to Jira]

amq commented 6 years ago

A rather interesting change in ARM Compiler documentation:

6.9

The default language standard for C code is gnu11. The default language standard for C++ code is gnu++98. To specify a different source language standard, use the -std=name option.

6.10

The default language standard for C code is gnu11 [COMMUNITY]. The default language standard for C++ code is gnu++14 [BETA]. To specify a different source language standard, use the -std=name option. For C++ code, Arm recommends compiling with -std=c++11. [Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

@pan-

To use lambda in Callback, there's no need to use the helper mbed::callback; just use the constructor

Doesn't work.

InterruptIn intpt(p12);
Callback myISR([]{ DigitalOut led1(LED1, 0); }); // 0 == on
intpt.rise(myISR);
[line 2]: error: missing template arguments before 'myISR'
    Callback myISR([]{ DigitalOut led1(LED1, 0); }); // 0 == on
             ^~~~~
[line 2]: error: expected primary-expression before ')' token
    Callback myISR([]{ DigitalOut led1(LED1, 0); }); // 0 == on
                                                  ^
[line 3]: error: 'myISR' was not declared in this scope

Even if there is a way to get that to work, how do I assign the lambd to a variable first, and then create the Callback from it?

it would be interesting to be able to store a std::function object in mbed::callback if application doesn't care about memory fragmentation and wants to use memory allocation.

I'm no longer personally interested in that, for those reasons. I'm happy to create mbed::Callbacks from my lambdas with an arbitrary number of captures. (Still, moving to C++11/14 and upgrading Callback will be good, but it's not a current need for me.) [Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

@amq

The default language standard for C++ code is gnu++14 [BETA]. ...Arm recommends compiling with -std=c++11.

They recommend using something other than their default? πŸ˜• ❓ [Mirrored to Jira]

amq commented 6 years ago

That's right. The same in the Release Note:

[SDCOMP-47596] The default C++ source language mode has changed from gnu++98 to gnu++14.

gnu++14 language and library features are a [BETA] product feature. Arm recommends compiling with -std=c++11 to restrict Arm Compiler to using only C++11 language and library features, which are fully supported. [Mirrored to Jira]

pan- commented 6 years ago

@bmcdonnell-ionx Id does work but mbed::callback like std::function is a class template:

InterruptIn intpt(p12);
mbed::Callback<void()> myISR([]{
    DigitalOut led1(LED1, 0);
}); // 0 == on
intpt.rise(myISR);

// or 

InterruptIn intpt(p12);
intpt.rise([]{
    DigitalOut led1(LED1, 0);
});

Both of the forms above work. The form you written is possible with C++17 with the help of the class template argument deduction feature (it requires a user defined deduction guide). [Mirrored to Jira]

geky commented 6 years ago

This leads to horrible compile time error: @geky Would it be possible to remove this line. It is incorrect (uintptr_t ???) and size verification happens in generate.

I'm not opposed to that.

It does remove the ability for the user to provide an alternative overload for the callback funciton due to ambiguity. But only if the class has a call operator. But this would also be a problem for std::function so I'm not sure it's something we care about. For example:

Callback<void()> callback(const Beeper &) {
    // blablabla
}

// Assuming beep had overloaded operator() for some reason, this may not compile
Beeper beep;
Ticker.attach_ms(300, mbed::callback(beep));

Adding a 24 byte field (char function_buffer[24]) in the _func union allow uses of std::function objects in callback:

That's quite a lot actually... And isn't it compiler dependent, or is 24 bytes expected across all compilers? (maybe we should have a compile time check in a test). This almost doubles the callback size in all existing classes.

But it might be worth it, allowing the user to opt-in to memory allocation and pass a std::function to mbed class would be valuable.

lambdas, variadic templates, class template argument deduction

C++11 is going to be exciting

[Mirrored to Jira]

pan- commented 6 years ago

I'm not sure to understand why it removes any ability. I'm just proposing the following replacement:

#define MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)                            \
    typename detail::enable_if<                                             \
            detail::is_type<M, &F::operator()>::value &&                    \
            sizeof(F) <= sizeof(uintptr_t)                                  \
>::type = detail::nil()

// replaced by: 

#define MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)                            \
    typename detail::enable_if<                                             \
            detail::is_type<M, &F::operator()>::value                     \
>::type = detail::nil()

With that change MBED_ENABLE_IF_CALLBACK_COMPATIBLE does not verify that the F size is compatible with Callback. It's sole responsibility is to ensure that F is a function like object. Therefore it does not discard the expected Callback constructor overload and we do no end up with compile time error messages listing all possible constructor (18!) and an obscure reason explaining why they don't match the parameter.

This change select the right constructor and move failure due to size of F into Callback::generate. The error message present in the MBED_STATIC_ASSERT is then displayed.

That's quite a lot actually... And isn't it compiler dependent, or is 24 bytes expected across all compilers? (maybe we should have a compile time check in a test). This almost doubles the callback size in all existing classes.

Yeah, thinking about that we may have better solutions to tackle the problem and they are easy to write in modern C++

[Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

@pan-

Both of the forms above work.

Yes, thanks for that. But it fails if I add two or more captures.

Arguably OT now; I can take this somewhere else if you want, but hopefully this is the last one...

What am I doing wrong here?

   int i0 = 0;
   int i1 = 1;

   InterruptIn intpt(p12);
   auto lambda = [&i0, &i1]{ DigitalOut led1(LED1, 0); }; // 0 == on
   Callback<void()> myISR(lambda);
   intpt.rise(myISR);

[Mirrored to Jira]

geky commented 6 years ago

Yeah, thinking about that we may have better solutions to tackle the problem and they are easy to write in modern C++

Still may be worth it! That's where I'm leaning, the less things that work the more surprises for users.

I'm not sure to understand why it removes any ability.

Currently we can do something like this:

Callback<void()> mbed::callback(std::function<void()> f) {
    // dynamically allocate a wrapper around f to shove it into a callback
    auto payload = new std::function<void()>(f);
    return mbed::callback([payload]() {
        (*payload)();
        delete payload; // note in real life you probably wouldn't want to delete here...
    });
}

int main() {
    // ADL for callback function takes over
    ticker.attach_ms(std::function<void()>([big_stuff]() { printf("hi"); }), 1000);
}

Is this worth is? I'm not sure

Also does this actually work? I'm not sure there either, it may need an additional enable_if to only make the callback overload available if it doesn't fit in the smaller callback... [Mirrored to Jira]

geky commented 6 years ago

@bmcdonnell-ionx, unfortunately callback only supports a single pointer/reference of storage. This is the cost of not allowing dynamic memory allocation.

If you create a struct and pass a reference to that struct it should work, although it is uglier. Feel free to correct me @pan- if there's a nicer way.

struct {
   int i0;
   int i1;
} i;
i.i0 = 0;
i.i1 = 1;

InterruptIn intpt(p12);
auto lambda = [&i]{ DigitalOut led1(LED1, 0); }; // 0 == on
Callback<void()> myISR(lambda);
intpt.rise(myISR);

[Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

@geky

unfortunately callback only supports a single pointer/reference of storage...

If you create a struct and pass a reference to that struct it should work...

Ah, well that explains why this works. Thanks.

   int i0 = 0;
   int i1 = 1;
   int i2 = 2;
   int i3 = 3;
   int i4 = 4;
   int i5 = 5;

   InterruptIn intpt(p12);
   auto lambda = [&i0, &i1, &i2, &i3, &i4, &i5]{ DigitalOut led1(LED1, 0); }; // 0 == on
   Callback<void()> myISR(&lambda, &decltype(lambda)::operator());
   intpt.rise(myISR);

[Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

@geky

Currently we can do something like this:

Callback<void()> mbed::callback(std::function<void()> f) {
    // dynamically allocate a wrapper around f to shove it into a callback
    auto payload = new std::function<void()>(f);
    return mbed::callback([payload]() {
        (*payload)();
        delete payload; // note in real life you probably wouldn't want to delete here...
    });
}

int main() {
    // ADL for callback function takes over
    ticker.attach_ms(std::function<void()>([big_stuff]() { printf("hi"); }), 1000);
}

Is this worth is? I'm not sure

Also does this actually work?...

If you do come up with some reason to implement Callback<void()> mbed::callback(std::function<void()> f) or &f (again, I'm not asking for it), consider not doing that extra dynamic allocation. Rather, just capture a reference to f, and count on the user to ensure it lives through its use.

Callback<void()> mbed::callback(std::function<void()> &f) {
    // dynamically allocate a wrapper around f to shove it into a callback
    return mbed::callback([&f]() {
        f();
    });
}

int main() {
    // ADL for callback function takes over
    std::function<void()>func([big_stuff]() { printf("hi"); });
    ticker.attach_ms(func, 1000);
}

[Mirrored to Jira]

geky commented 6 years ago

@bmcdonnell-ionx, good point, we should add an overload for an indirect reference. I would just use a pointer so it's clear at call time:

// who owns the function?
std::function<void()>func([big_stuff]() { printf("hi"); });
ticker.attach_ms(func, 1000);

vs

// I own the function
std::function<void()>func([big_stuff]() { printf("hi"); });
ticker.attach_ms(&func, 1000);

[Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

My point was not so much about reference vs value, but rather about avoiding dynamic memory allocation. [Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

@pan-

Unlike std::function, mbed::callback does not use dynamic memory to store its inner function like object. This is by design to avoid invisible memory fragmentation and possible memory allocations in interrupt context. Of course it limits the number of parameters that a lambda can capture.

~I agree with the design decision, but it seems it hasn't been followed.~

~For instance, Callback.h. Do a find on new on that page, you'll see many allocations.~

~Was this intentional?~

~Or did you mean to say that it doesn't use dynamic memory for that one thing, even though it uses it for others?~

[EDIT] Related: https://github.com/ARMmbed/Handbook/issues/499

[EDIT 2]: Sheesh, these are placement news, right? Meaning they're statically allocated in-place, on the stack, right? My mistake, it seems. πŸ™ [Mirrored to Jira]

pauluap commented 6 years ago

Talk about std::function has been popping up more often now. I might as well as go for a total hijack, @bmcdonnell-ionx , @geky, I agree that wholesale use of std::function isn't a good idea due to the dynamic memory allocations. The small size optimization is implementation-dependent. I've built my code across several compilers/platforms and there's no consistent pattern.

I didn't (don't) see how to preallocate space or restrict to the small-size optimized size for usage of std::function

However, it's certainly possible to construct a std::function-like object that has determistic memory. I've been using this https://github.com/LoopPerfect/smallfunction and it's working effectively for me so far.

As far as mbed::Callback is concerned though, smallfun isn't a perfect solution since its size is a template parameter. Either accept a larger default systemwide size or make the functions that accept mbed::Callback be templated.

I wouldn't be surprised if there was a solution that I haven't thought of, but I feel that currently, as std::function is specified in the C++ standards, using it should be an user choice, not system-enforced. [Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

@pauluap, @pan-,

FYI, see my "[EDIT 2]" above. [Mirrored to Jira]

pauluap commented 6 years ago

Yup, but not quite exactly. static has multiple meanings, but this usage isn't one of them. Placement new isn't necessarily on the stack (nor the heap), but wherever the object (existing or not) resides. "stack" and "heap" are language abstractions.

Those probably explain better than I can

http://en.cppreference.com/w/cpp/language/new http://en.cppreference.com/mwiki/index.php?title=Special%3ASearch&search=static

[Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

You're right (AFAICT) that placement new doesn't specify the storage type. I inferred that it's either on the stack, or under the user's control, but I don't know that. Interested in learning more.

That said, IME, "statically" allocated doesn't necessarily mean declared with keyword static. And I already linked to the new cppref page right above. [Mirrored to Jira]

pauluap commented 6 years ago

Sorry! It's a great reference site.

Placement new works with objects on the stack or heap

#include <new>

struct A {
  A(int a) : a(a) {}
  int a;
};

int main(void) {
  A stackA{1};
  A* heapA = new A{2};
  A* pStackA = &stackA;

  stackA.~A();
  heapA->~A();

  new (pStackA) A{3};
  new (heapA) A{4};

  pStackA->~A();
  delete heapA;
}

There's lots of ways to go wrong though. While this code compiles on GodBolt, I wouldn't trust it without some unit tests. I don't think that I need to explicitly call the destructor as in heapA->~A() before delete here because the object isn't cast from void, but I do have to manually destruct pStackA because the name stackA was already destroyed from the compiler point of view. I could be wrong. In multiple ways. When I really need to do this, I relearn it, stuff the code in a wrapper and immediately forget everything again.

here's an entrance to a rabbit hole - http://www.dietmar-kuehl.de/mirror/c++-faq/dtors.html#faq-11.10 [Mirrored to Jira]

pan- commented 6 years ago

@pauluap Unfortunately, there's no one size fits all solution that solves the callable abstraction problem. It's a tradeof between simplicity, usability, implementation complexity and memory footprint (ROM and RAM). We may reconsider (it was at some point) the addition of a template parameter that controls the size of the inner buffer if it's a strong requirement coming from users. Right now callbacks are mostly used to store either a function pointer or a pointer to an object and the member function to call very few users actually use it to store function like object as those are really verbose in C++03. Usage might change if we supports C++11 as lambda are easy to write but we must remain attentive to memory consumption.

Regards to the uses of placement new, it can be used to recycle a manually destroyed object; it's also great with allocators. Starting with C++11, aligned_storage is available and ease the creation of objects that shouldn't be initialized right away.

Note that there's an error in your code as stackA is destroyed twice: the first time with expression pStackA->~A(); and the second time with the automatic call to the destructor at the end of the scope.

[Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

@pan-

We may reconsider (it was at some point) the addition of a template parameter that controls the size of the inner buffer if it's a strong requirement coming from users.

Can you do sizeof on the given template parameters to determine the buffer size? [Mirrored to Jira]

pan- commented 6 years ago

@bmcdonnell-ionx Like std::function; the template parameter of mbed::Callback is the signature of the call abstracted; not type held by the object. So no, sizeof is not applicable in this case. If you know the type of the callable that will be used beforehand then use it; there's no point in adding another layer of indirection. [Mirrored to Jira]

pauluap commented 6 years ago

@pan- Heh, that comes to absolutely no surprise that there's an error in my code. That's a confusing spot to me, my research has indicated that if a label is deleted (stackA.~A()) any use of the name afterwards is undefined behavior. That suggests to me that the generated code wouldn't call the destructor on scope exit. I ran across that a very long time ago though, and my google-fu isn't working in finding the original source where I saw it. There's a non-remote possibility that I'm completely and utterly wrong, of course.

The point that I was trying to make was to disencourage wholesale replacement with std::function and bring up a potential approach in using function-like object libraries that provide support for deterministic memory usage such as smallfunction

Templatizing the users of mbed::Callback is a large impact, because currently most if not all attach functions (InterruptIn::rise, Socket::sigio) are themselves not templates, but accept a fixed type of mbed::Callback<void()>

I personally have no real suggestions as to the 'replacement' for mbed::Callback - it's a hard problem especially since any change would be breaking changes.

At the end of the day, it boils down to memory management. With std::function, the machinery for scope capture is really nice and hides a lot of things behind the curtain. Creating a function object to contain local data and passing it as a mbed::Callback function object pointer ultimately does the same thing with the exception that the lifetime management onus for the function object is on the programmer. [Mirrored to Jira]

pan- commented 6 years ago

@pauluap undefined behaviour means that the behaviour is not specified by the C++ standard. In other words, anything can happen; in this case it will most likely call the destructor at the end of the scope; there's little chance it doesn't call the destructor and that chance would be compiler specific. Better to not try it. As a rule of thumb you must avoid undefined behaviour at all cost if you don't want funny surprises when the code evolve, the compiler change or the optimisation change.

Adding a size parameter to mbed::Callback wouldn't be a source breaking change as we can add a default value for this parameter. However it definitely is an ABI breaking change.

As letting lifetime management up to the user it is already possible to construct a non owning Callback from the object and it's call opererator. The creation process could be simplified with the adjunction of a builder function like mbed::callback does. However it exposes to the user APIs that are easy to misuses so it requires evaluation. Constraints in in this area are mostly not technical. [Mirrored to Jira]

pauluap commented 6 years ago

Yes, I certainly can agree that wrapping easily misused parts is something that's very desirable.

Adding a size parameter would be cool, making mbed::Callback have characteristics that attracted me to smallfunction. If such a addition was made to mbed::Callback I'd gladly drop my usage of smallfunction if the implementation also adds the ability to cast lambdas to mbed::Callback, that would be super awesome. That's a feature of std::function that I really love. Using lambdas ends up being better optimized memory-wise than using std::bind and friends.

However, that wouldn't help users of existing APIs that accept mbed::Callback such as Socket::sigio and others because given that the sigio function isn't templated, the mbed::Callback type would have a fixed size, and I wouldn't be surprised if a war erupted if somebody suggested increasing the default size.

Just converting those API member functions to templates wouldn't work. the class itself would then have to be templated on the callback type to hold the callback object as a member variable.

[Mirrored to Jira]

bmcdonnell-ionx commented 6 years ago

@pan-, @pauluap, would it make more sense to continue the mbed::Callback discussion in a separate issue? [Mirrored to Jira]

adbridge commented 5 years ago

Internal Jira reference: https://jira.arm.com/browse/IOTCORE-251

amq commented 5 years ago

Looks like C++14 is out of beta in Arm Compiler 6.11

idea--list commented 5 years ago

Hi there,

I am learning C++ right now for an embedded project. I notice the way one should code depends also on the C++ standard. As i see the online mbed compiler still compiles in C++98, which i find quite odd to say the least even as a beginner.

My question is: Is there a way i can change the setup of the online compiler to C+11 or C+14 standards? If not can i just write my code locally in C++11 without using mbed-os (that seems to be outdated) and just upload a locally compiled bin to my board?

theotherjimmy commented 5 years ago

@idea--list You cannot change the C/C++ standard in the online compiler. You can compile locally and upload a .o. Be aware that the online Compiler uses ARM Compiler (5 or 6 depending or arch version). You may be best served by Mbed CLI + GCC ARM.