wg21-sg14 / sg14 Goto Github PK
View Code? Open in Web Editor NEWA library for Study Group 14 of Working Group 21 (C++)
A library for Study Group 14 of Working Group 21 (C++)
Shouldn't the friend declaration of ring_iterator
's operator+=()
and operator-=()
be
template< class R, bool C >
friend ring_iterator<R,C> & operator+=( ring_iterator<R,C> & it, int i ) noexcept;
template< class R, bool C >
friend ring_iterator<R,C> & operator-=( ring_iterator<R,C> & it, int i ) noexcept;
instead of
friend type & operator+=( type & it, int i ) noexcept;
friend type & operator-=( type & it, int i ) noexcept;
GNU C++ 5.2 warns (-Wnon-template-friend)
Right now, inplace_function
permits
auto lam = [i=0]() mutable { return ++i; };
const stdext::inplace_function<int()> f(lam);
f();
That is, if I have a reference to a const inplace_function
, I can call its operator()
, which can mutate its internal state, even though I've promised not to modify it!
I believe we ought to follow the lead of Folly::Function, fu2::function, etc., and split inplace_function
into two kinds of specialization:
inplace_function<R(As...)>
is constructible from either const-callable or non-const-callable lambdas, and provides only operator()
(non-const)
inplace_function<R(As...) const>
is constructible only from const-callable lambdas, and provides only operator() const
In this paradigm, you would not be permitted to write
int one(const inplace_function<int(int)>& f) {
return f(1) + f(2);
}
int two() {
auto mutlambda = [i = 0](int j) mutable { return i += j; };
return one(mutlambda);
}
The call to f(1)
would fail to compile because inplace_function<int(int)>::operator()(int)
is not const-qualified. Instead, you would have to write either
int one(const inplace_function<int(int) const>& f) {
return f(1) + f(2);
}
int two() {
int i = 0;
auto nonmutlambda = [&i](int j) { return i += j; };
return one(nonmutlambda);
}
or
int one(const inplace_function<int(int) const>& f) {
return f(1) + f(2);
}
int two() {
auto mutlambda = [i = 0](int j) mutable { return i += j; };
return one(std::ref(mutlambda));
}
or
int one(inplace_function<int(int)> f) {
return f(1) + f(2);
}
int two() {
auto mutlambda = [i = 0](int j) mutable { return i += j; };
return one(mutlambda);
}
depending on the semantics you want.
Currently there is no licensing information for algorithm_ext.h
ring.h
and transcode.h
. This should probably be added if the code should be used by others.
in:
template <typename T>
T sg14::copy_popper<T>::operator()(T& t)
{
T old = t;
t = copy;
return t;
}
shouldn't return t
be return old
?
operator >
in
return (m_idx > rhs.m_idx) && (m_rv == rhs.m_rv);
should be >=
.
This is a really unfortunate side-effect of a core language issue, IMNSHO; this week I have been actively working on trying to understand and diagnose the core issue. CWG 1579 is related but its resolution left much to be desired.
Consider this program:
using IPF20 = stdext::inplace_function<void(), 20>;
using IPF40 = stdext::inplace_function<void(), 40>;
static_assert(std::is_convertible<IPF20, IPF40>::value, "");
IPF40 foo() {
IPF20 f;
return f; // HERE
}
What happens on the line marked "HERE"? Naively, we would expect NRVO (copy elision). But that can't happen because IPF20 and IPF40 are not the same type. So, post-CWG1579, we would expect lvalue-to-rvalue conversion — we'd expect that the expression f
is treated as an rvalue, and the wrapped functor is moved from f
into the return slot. However, CWG1579 kicks in only for constructors; it does not kick in for inplace_function
's clever use of a templated conversion operator to implement implicit conversions. So CWG1579 does not kick in, and what we actually get in this case is a copy operation.
SG14 could fix this by changing the implementation of implicit conversions for inplace_function
to use converting constructors instead of conversion operators, but this strikes me as a library fix for a language bug. I am pessimistic but not fatalistic that we might actually be able to get a core language fix here. I'm opening this GitHub issue just to document the issue for posterity.
(I remember remarking on @Voultapher's unusual and clever use of conversion operators at the time. He convinced me that it was the Right Way to do it, and I still think it is, really. But I'm sad to see that it actually does have minor negative consequences due to this core language bug.)
When using slot_map for components and such, one would usually implement a disable feature. This is done using a pivot, and swapping disabled elements to the end of your contiguous container. Iterating the "enabled" data will thus be contiguous.
I don't think the standard would ever accept a container with this kind of state. So a way to enable this should be provided. From my uses so far, I think a simple id_swap(Key old, Key new)
would enable a lot of needed flexibility.
For disabling components, one could create 2 slot_maps
, enabled and disabled, and move objects between the 2. The only problem then is users will have copies of the original id. Adding id_swap
lets you move into a disabled slot_map
, swap the id to the old one, never invalidating user owned ids.
There are other uses for id_swap
. When using RAII to keep user ids valid, the copy constructor would need such a thing.
Ultimately, you want to keep iterators valid when moving/swapping/deleting objects. id_swap
is just an idea, there may be better ways.
As class ring_iterator<>
needs access to private ring_span<>::at()
.
A problem I just discovered with the current assert
-based testing is that the tests disappear in Release (or RelWithDebInfo) builds.
I'd suggest Catch since it's single-header, has reasonable clear syntax, and supports good DRY behaviours and BDD terminology.
I'm also happy to go ahead and do the conversion, this would help clean-up the current tests which are lumped together into a single executable, and one test currently prompts the user for input.
I'd probably go ahead and restructure the CMake a bit too, to take advantage of unit-testing support and allow testing individual tests. Currently compile failures in one test block the other tests completely.
See Arthur O'Dwyer's reference implementation std::ring_span.
I would like to challenge some decisions made in P0661r1 from SG14.
P0661r2 states the following question was asked and answered.
R1 | Should raw access to the underlying container be provided? | No. | SG14
This is inconsistent with the current behavior, as the container returns the underlying container iterators. This means you already have access to the underlying container either through begin
and end
.
I believe const
access to the underlying container should be available, at a minimum. I would prefer full access to the underlying container. See my next contention point for more details on why this is preferred.
Another decision I would like to challenge is direct access to the underlying container iterators.
It also provides the following iterator type aliases. Note that the adapted container must provide iterators satisfying the constraints of RandomAccessIterator.
using iterator = typename Container<value_type>::iterator;
using const_iterator = typename Container<value_type>::const_iterator;
using reverse_iterator = typename Container<value_type>::reverse_iterator;
using const_reverse_iterator = typename Container<value_type>::const_reverse_iterator;
The access to the underlying container iterators is dangerous. I've already shot myself in the foot assuming coherent behavior between slot_map
iterators and its keys. I believe many more will.
Furthermore, it precludes using standard algorithms like std::partition
. I fear the slot_map
api will grow, with many custom cases that will need special implementations. It is already starting : #133
An alternative would be to provide custom, "smart and safe", iterators that do not invalidate the relationship between keys and elements stored in the container. Iterator swap
, for example, should swap elements and shouldn't invalidate keys. In fact, no iterator operation should invalidate keys, ever.
This may make slot_map
iterators heavy or less performant (TBD in test implementation), which may be a problem. Again, I believe direct access to the underlying container would be a better way to deal with this issue. When a user accesses the underlying container, it is clear he is in "no mans land". When you use slot_map
iterators, operations should be safe, always.
Currently, using slot_map
iterators is no mans land... Yet SG14 doesn't agree underlying container access is a good idea. This doesn't seem coherent.
I would appreciate some feedback on the types of pitfall you may fall into with custom iterators.
Thank you, looking forward to your feedback.
Maybe I'm doing something wrong, but...
CMakeFiles/sg14.dir/home/carlcook/workspace/sg14/SG14/SG14_test/main.cpp.o: In function `main':
main.cpp:(.text+0x10): undefined reference to `sg14_test::transcode_test()'
main.cpp:(.text+0x15): undefined reference to `sg14_test::ring_test()'
main.cpp:(.text+0x1a): undefined reference to `sg14_test::thread_communication_test()'
collect2: error: ld returned 1 exit status
CMakeFiles/sg14.dir/build.make:172: recipe for target 'sg14' failed
make[2]: *** [sg14] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/sg14.dir/all' failed
make[1]: *** [CMakeFiles/sg14.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
~/workspace/sg14/SG14/cmake (master *)$
Just to let you know:
https://github.com/user706/CxxFunctionBenchmark/tree/feature/sg14_inplace_function
(awaiting pull request... to main benchmark project here)
I can generate some example cases if you guys are unaware of this circumstance, but just wanted to bring it up to confirm.
All my inplace functions are usually at most a few hundred bytes, but sometimes in order to compile one will suddenly require like 10,000 bytes! (so about 2 orders of magnitude more space). I suspect it's when you have inplace functions inside inplace functions (but leaving certainty on that aside for now).
ring_span is not a semiregular type, because it (and its iterator) lack default constructors. There may be other operations missing. Assuming addition of these does not negatively impact performance, it would be nice for both libraries to interoperate without friction.
For example, see here: https://godbolt.org/z/U3a2GX
#include <string>
#include "inplace_function.h"
std::string global_dummy;
void take(std::string&& s)
{
global_dummy = std::move(s);
}
int main()
{
/// comment this and uncomment the std::function line to make it compile
stdext::inplace_function<void(std::string&&)> func(take);
//std::function<void(std::string&&)> func(take);
std::string s = "1234567";
func(std::move(s));
}
This code works as expected with std::function, but doesn't compile with inplace_function, complaining that (exact phrasing depends on compiler, but the same error message appears in all of them):
error: cannot bind rvalue reference of type 'std::__cxx11::basic_string&&' to lvalue of type 'std::__cxx11::basic_string'
If I understand it correctly, the problem is that operator() can't use a forwarding reference for the function arguments because they are not deduced in the function (they are parameters of the class template).
The standard library implementations solve this somehow. This rabbit hole was too complicated for me to follow.
I'm trying to find the keys of stored objects that match a given predicate. I can't see any api to get a key from an iterator, but I may be missing something.
Is it possible to get a key using an iterator in slot_map
?
As demonstrated here, SG14 is needs some changes in order to make it more accessible by more people. In particular, the three main audiences of the repository / organization are:
GitHub is naturally better suited to 1), OK for 2) and troublesome for 3).
Suggested improvements include:
It would be very useful to have proper CMake installation support for the library. Then Conan support would also be trivial to add. Currently we have to fork the repo and write our own custom wrappers over SG14 or even copy the headers directly which is suboptimal since we then have to sync with the upstream version manually.
My copy of Visual Studio 2015 does not accept the toolchain specified in the vcxproj files. It states that the given toolset is not installed. If I change the toolset back to just v140 as it used to be instead of Visual Studio 2015 (v140) then it works properly.
https://wandbox.org/permlink/nT7NOhnVm2JZopjh
stdext::inplace_function<void(), 16> f;
f = []() { puts("hello world"); };
stdext::inplace_function<void(), 16> g; // bonus: change 16 to 17 and it should still work
g = f; // ERROR!
Oddly, it does work for move-assignment!
I think the issue is some SFINAE on the wrong overload. Should be:
template<typename Callable, class = typename std::enable_if<!std::is_lvalue_reference<Callable>::value>::type>
inplace_function& operator=(Callable&& target)
That SFINAE looks sketchy to me anyway, but it seems to DTRT.
I remember some talks on the mailing list of a conan organization. Has this materialized?
See Arthur O'Dwyer's reference implementation std::ring_span.
Hi,
I am trying to use slot_map with a custom key:
template <typename T>
class VariableKey : public std::pair<unsigned, unsigned>
{
typedef T variable_type;
// Slot Map key (index, generation).
bool operator<(const VariableKey<T> &other)
{
this->first < other.first;
}
};
This causes this error:
clang: error: unable to execute command: Segmentation fault: 11
clang: error: clang frontend command failed due to signal (use -v to see invocation)
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
clang: note: diagnostic msg: PLEASE submit a bug report to http://developer.apple.com/bugreporter/ and include the crash backtrace, preprocessed source, and associated run script.
clang: note: diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: /var/folders/mm/mdrm14d96yqgjfyyfw6zyfq00000gn/T/TestSlotMap-cdca70.cpp
clang: note: diagnostic msg: /var/folders/mm/mdrm14d96yqgjfyyfw6zyfq00000gn/T/TestSlotMap-cdca70.sh
clang: note: diagnostic msg: Crash backtrace is located in
clang: note: diagnostic msg: /Users/kevinsheridan/Library/Logs/DiagnosticReports/clang_<YYYY-MM-DD-HHMMSS>_<hostname>.crash
clang: note: diagnostic msg: (choose the .crash file that corresponds to your crash)
clang: note: diagnostic msg:
********************
make[2]: *** [tests/CMakeFiles/runTests.dir/TestSlotMap.cpp.o] Error 254
make[1]: *** [tests/CMakeFiles/runTests.dir/all] Error 2
make: *** [all] Error 2
If you declare a volatile inplace_function<...>
variable you cannot call any or almost any methods on it, including operator()()
, bool operator()
, etc., presumably because volatile overloads for those are missing and the compiler refuses to use any overloads not marked volatile.
As you have probably guessed, I do bare metal programming and the variable I want to make volatile is accessed both from thread mode and an interrupt handler (for example, a timer interrupt calls a callback stored in a variable and sets it to empty). While I'm admittedly not entirely sure how necessary it is (it probably depends on many factors), this is a very common practice in embedded programming and I don't feel safe having to omit volatile. I see that there is effort being made to support embedded environments (e. g. 3b81451) which is a very good sign from my perspective. Would you be willing to consider adding volatile overloads?
Related to #149.
static void test_void_returning_function()
{
stdext::inplace_function<void()> f = []() { return 42; };
f = []() { return 42; };
f();
}
The above test case currently does not compile. Clang's error message is:
In file included from inplace_function_test.cpp:2:
../SG14/inplace_function.h:105:15: error: void block should not return a value
{ return (*static_cast<C*>(storage_ptr))(
^
../SG14/inplace_function.h:211:31: note: in instantiation of function template specialization 'stdext::inplace_function_detail::vtable<void>::vtable<(lambda
at inplace_function_test.cpp:412:42)>' requested here
static const vtable_t vt{inplace_function_detail::wrapper<C>{}};
^
inplace_function_test.cpp:412:42: note: in instantiation of function template specialization 'stdext::inplace_function<void (), 32,
16>::inplace_function<(lambda at inplace_function_test.cpp:412:42), (lambda at inplace_function_test.cpp:412:42), void>' requested here
stdext::inplace_function<void()> f = []() { return 42; };
^
If we fix #149, then we must make a design decision here: should this code compile (as it does with std::function
), or should it fail to compile (because returning 42
from a function with signature void(int)
usually indicates a programming error)? https://quuxplusone.github.io/blog/2019/01/06/hyper-function/ is related.
Currently, slot_map
doesn't have many constructors one has come to expect. Adding slot_map(size_type count)
and slot_map(size_type count, const T& value)
would rank top for my needs. Eventually, mimicking applicable std::vector
constructors would be welcome.
Maybe I'm missing a point, but having a clear()
member function seems rather useful [popping them one by one vs. doing it O(1)] to me. Iff the It is assignable, but not how I tried to do that. So if I have a sg14::ring_span
would be assignable, I could do without, but that doesn't seem to be the case either.sg14::ring_span
as a class member, the only option is to pop till it drops :-) .
Sorry for putting this issue on the SG14 repo, I couldn't see a good place on github to otherwise post a message to @WG21-SG14/sg14, as suggested last July in https://groups.google.com/a/isocpp.org/d/msg/sg14/1yRloYFAkhs/Aq91OGjcBQAJ
Now that I have https://github.com/TBBle/SG14-comparing-virtual-functions functional, I have decided it makes more sense for the master copy (i.e. the one with github pages and an Issue Tracker) to be under the WG21-SG14 organisation.
According to https://help.github.com/articles/transferring-a-repository-owned-by-your-personal-account/ this means I need "admin or owner" permissions with the receiving organisation.
If there's any concerns, I'm happy to subsequently be restricted to admin permissions on this specific repo once it's moved.
On the other hand, you may also consider this an offer to volunteer for organisation maintenance duties. ^_^
At the moment a default-constructed inplace_function
is not safe to call (depending on SG14_INPLACE_FUNCTION_THROW). IMO it would be interesting to be able to opt-in to a behaviour where at least inplace_function<void(...), ...>
can be safely used from default-constructed instances. Optionally (or a second opt-in?) where inplace_function<R(...), ...>
returns std::declval<R>()
would potentially be interesting as well.
Currently, unstable_remove
algorithm takes argument v
by value, which can involve unnecessary copying. Should it take the argument by const reference instead?
The following test fails for me locally:
static_assert(safe_add<std::uint8_t, -4>(15, 13).get<int>() == 28, "sg14::safe_add test failed");
C:\Dev\sg14\SG14\SG14\fixed_point.h(615): error C2338: mismatched safe_add parameters
C:\Dev\sg14\SG14\SG14\fixed_point.h(623): note: see reference to function template instantiation 'RESULT_TYPE sg14::_impl::add<RESULT_TYPE,REPR_TYPE,-4,int>(const HEAD &)' being compiled
with
[
RESULT_TYPE=output_type,
REPR_TYPE=uint8_t,
HEAD=int
]
C:\Dev\sg14\SG14\SG14\fixed_point.h(632): note: see reference to function template instantiation 'RESULT_TYPE sg14::_impl::add<output_type,REPR_TYPE,-4,sg14::fixed_point<REPR_TYPE,-4>,int>(const HEAD &,const int &)' being compiled
with
[
RESULT_TYPE=output_type,
REPR_TYPE=uint8_t,
HEAD=sg14::fixed_point<uint8_t,-4>
]
......\SG14_test\fixed_point_test.cpp(223): note: see reference to function template instantiation 'sg14::fixed_point<REPR_TYPE,-3> sg14::safe_add<uint8_t,-4,int>(const sg14::fixed_point<REPR_TYPE,-4> &,const int &)' being compiled
with
[
REPR_TYPE=uint8_t
]
......\SG14_test\fixed_point_test.cpp(72): note: see reference to class template instantiation 'sg14::fixed_point<uint8_t,0>' being compiled
This was feedback I received from Louis Dionne during the SG14 meeting at CppCon.
The idea is that with Folly (being a unique function), there might actually be lots of use cases of different storage types (and other behaviours), and then we will get an explosion of new types (e.g. std function, move-only function, inplace function). Maybe it is best to do what std::basic_string does, where Traits are used to provide the implementation details.
So basically the standard focuses on basic_function, and then inplace function is a second proposal that builds on basic function, providing traits where memory allocation is inplace.
Right now, the following program performs poorly:
https://wandbox.org/permlink/vLEl9Owmp1exrkKA
struct Widget {
Widget() {}
Widget(Widget&&) noexcept { puts("move"); }
Widget(const Widget&) noexcept { puts("copy"); }
};
auto f = [w = Widget()]() {};
using IPF = stdext::inplace_function<void(), 32>;
std::vector<IPF> v;
v.emplace_back(f);
v.emplace_back(f);
[...]
The vector resize does copy
instead of move
, because inplace_function
's move constructor is not marked noexcept
, and vector is pessimized in that case.
I'd like to see us explicitly drop support for non-noexcept-moveable types, preferably by specifying that the move constructor will call std::terminate
if the wrapped object throws during its move-construction. Then the patch to de-pessimize the vector code above would be a single keyword: just add noexcept
to the move constructor. (And to swap
; and optionally to move-assignment.)
@carlcook thoughts?
Couldn't the memory algorithms take advantage of type traits to avoid performing unneeded operations? For example, it should be possible to use tag dispatch on std::is_trivially_destructible
in destruct
to turn it into a no-op when T
is indeed trivially destructible. Also uninitialized_move
could take advantage of std::is_nothrow_move_constructible
to get rid of the exception handling when it's unneeded and could even fall back to std::memmove
when std::is_trivially_move_constructible
is true.
I guess that compilers can already perform some of these transformations, but I know that at least libc++ tends to use tag dispatch in such cases anyway. On the other hand, I could understand that this repository provides proof-of-concept algorithms and not state-of-the-art ones, but if anyone wants to just use them a is, it might be a valuable addition.
... due to something in the ring buffer:
In file included from /home/carlcook/workspace/sg14/SG14/SG14_test/SG14_test.cpp:6:0:
/home/carlcook/workspace/sg14/SG14/cmake/../SG14/ring.h:119:44: error: friend declaration ‘sg14::ring_iterator< <template-parameter-1-1>, <anonymous> >::type& sg14::operator+=(sg14::ring_iterator< <template-parameter-1-1>, <anonymous> >::type&, int)’ declares a non-template function [-Werror=non-template-friend]
friend type& operator+=(type& it, int i) noexcept;
^
compilation terminated due to -Wfatal-errors.
Just hit an issue when overloading a function accepting inplace_function
vs. std::function
. The compiler (MSVC 2017, clang 7) cannot disambiguate by function arguments. Here is a repro example and a link to it on compiler explorer.
Not sure if there is something to be done about this, worth investigating though.
#include <cstdio>
#include <functional>
#include <sg14/inplace_function.h>
// Something to be done about this?
/**
* Ambiguous
*/
void myfunc(stdext::inplace_function<void()>&& exec) {
std::invoke(exec);
}
void myfunc(stdext::inplace_function<void(size_t)>&& exec) {
std::invoke(exec, size_t(42));
}
/**
* Not ambiguous
*/
void myfunc_std(std::function<void()>&& exec) {
std::invoke(exec);
}
void myfunc_std(std::function<void(size_t)>&& exec) {
std::invoke(exec, size_t(42));
}
int main(int, char**) {
// ambiguous
myfunc([](){
printf("blee\n");
});
// ok
myfunc_std([](){
printf("blou\n");
});
return 0;
}
Good day
Is there a chance to have a non thread-safe shared_ptr in the standard?
I was thinking either as a new template or maybe the current shared_ptr should have a template parameter if it's ref counting should be atomic.
There is quite a bit of interest in such a thing - see here
Andrei Alexandrescu talked at the cppcon how to implement such a pointer yourself but I feel the standard should provide one - see here
If facebook are doing it - it must be valuable.
Currently the only publicly available solution seems to be building boost with a flag/define to disable thread-safe reference counting.
It might be also good to have the optimizations that Andrei talks about - for the common case when the ref count only goes to 1 and then to 0.
I've already asked this in the google groups for the c++ standard/discussions and I was told that I should make a proposal but I'm not gonna go that route myself just yet.
The throw std::bad_function_call();
in the default constructor of vtable
causes compilation failures when building with -fno-exceptions
.
What to do instead, I don't really know, but one of the use-cases I have for this is in an embedded setting and this is throwing a wrench in that unfortunately.
Missing from both proposal and reference code.
@mattreecebentley, as far as I understand, SG14.VC.db should not have been committed in 23dceac?
Unless I've overlooked something, I'll put up a pull request to remove it.
Seeing as inplace_function
is standard layout and cannot allocate, I assumed it would be safe (dependent on what is put in it, of course) to be used across shared library interfaces. Apparently this is not the case.
The mechanism used to identify an empty inplace_function
relies on taking the address of an inline constexpr
global. Perhaps this is specific to MSVC (obviously this is not specified by the standard), but in practice I'm seeing a default constructed function converting to false in one module, but to true (callable) in another module due to differing addresses of empty_vtable
.
Is usage across shared libraries a bad idea in general and intentionally not supported? If not, is this something that can be easily addressed?
Both folly::Function
and fu2::function
, as far as I can tell, make the following test case pass:
function<void()> foo = SomeFunctor{};
function<void()> bar;
assert(!bar);
bar = std::move(foo); // move the state from foo to bar...
assert(!foo); // ...leaving foo empty. (This assertion fails with inplace_function.)
To make this test case fail, you have to leave foo
in a sort of "partly moved from" state, where calling foo()
effectively has undefined behavior (because the contained SomeFunctor
object you're calling is in a moved-from state), which kind of defeats the purpose of having an "empty" (bad_function_call
-throwing) state at all.
On the other hand, if you do make this test case pass, then you end up with a strongly type-safe object type, where the object is fundamentally not allowed to enter a "nonsense" or "partly-moved-from" state. This strikes me as a good idea. I think inplace_function
should follow the example of Folly here, and make this test case pass.
On #116 @Voultapher writes:
@Quuxplusone thanks for your feedback so far! Something I noticed looking at the libcxx implementation, they seem to set their version of a vtable to 0, aka empty state, whenever they are about to copy or move. My best guess is, that its stack unwinding related. Can you come up with a test of a throwing copy assignment, that checks if the cleanup is done right?
I have been procrastinating on this. Creating this issue now so that it will not fall through the cracks when #116 is closed/merged.
Right now, it seems like cmake fails to find the plf tests. Commenting out this target works.
Let's say I have a static inplace function:
static stdext::inplace_function<void(embvm::i2c::status)> twim0_callback;
static stdext::inplace_function<void(embvm::i2c::status)> twim1_callback;
Later I set the value:
twim0_callback = cb;
Under this scenario, I end up with a hard fault within operator=(const inplace_function&)
, on this line:
vtable_ptr_->destructor_ptr(std::addressof(storage_));
I don't actually have a vtable pointer at this time, according to gdb:
(gdb) p vtable_ptr_
$3 = (stdext::inplace_function<void(embvm::i2c::status), 32, 8>::vtable_ptr_t) 0x0
This confuses me, because it seems like I should be using the address of empty_vtable
.
I'm encountering this with the following arm-none-eabi-gcc:
gcc version 8.2.1 20181213 (release) [gcc-8-branch revision 267074] (GNU Tools for Arm Embedded Processors 8-2018-q4-major)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.