boost-ext / te

C++17 Run-time Polymorphism (Type Erasure) library
451 stars 38 forks source link

Compilation of examples failed on gcc 9, 10 and 11 #36

Open YuraCobain opened 1 year ago

YuraCobain commented 1 year ago

Expected Behavior

Compilation of examples by gcc 9,10,11 is successfuly

Actual Behavior

Compilation is failed by gcc 9.4.0, 10.3.0 and 11.1.0 with following errors: Non-member CircleMember Square[ 92%] Built target unified [ 96%] Building CXX object test/CMakeFiles/te.dir/te.cpp.o In file included from /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/test/te.cpp:13: /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp: In instantiation of ‘constexpr boost::ext::te::v1::poly<I, TStorage, TVtable>::poly(T&&, std::indexsequence<Ns ...>) [with T = Square; T = Square; long unsigned int ...Ns = {}; I = DrawableT<std::basic_ostream >; TStorage = boost::ext::te::v1::dynamic_storage; TVtable = boost::ext::te::v1::static_vtable; std::index_sequence<Ns ...> = std::integersequence]’: /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp:463:68: required from ‘constexpr boost::ext::te::v1::poly<I, TStorage, TVtable>::poly(T&&, TRequires) [with T = Square; T = Square; TRequires = boost::ext::te::v1::detail::type_list; I = DrawableT<std::basic_ostream >; TStorage = boost::ext::te::v1::dynamic_storage; TVtable = boost::ext::te::v1::staticvtable]’ /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp:443:74: required from ‘constexpr boost::ext::te::v1::poly<I, TStorage, TVtable>::poly(T&&) [with T = Square; T = Square; typename std::enable_if<(! is_samev<T, boost::ext::te::v1::poly<I, TStorage, TVtable> >), bool>::type = true; I = DrawableT<std::basic_ostream >; TStorage = boost::ext::te::v1::dynamic_storage; TVtable = boost::ext::te::v1::static_vtable]’ /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/test/te.cpp:486:56: required from here /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp:475:33: error: static assertion failed 475 | static_assert(sizeof...(Ns) > 0); | ~~~~^ /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp: In instantiation of ‘constexpr boost::ext::te::v1::poly<I, TStorage, TVtable>::poly(T&&, std::indexsequence<Ns ...>) [with T = Circle; T = Circle; long unsigned int ...Ns = {}; I = DrawableT<std::__cxx11::basic_stringstream >; TStorage = boost::ext::te::v1::dynamic_storage; TVtable = boost::ext::te::v1::static_vtable; std::index_sequence<Ns ...> = std::integersequence]’: /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp:463:68: required from ‘constexpr boost::ext::te::v1::poly<I, TStorage, TVtable>::poly(T&&, TRequires) [with T = Circle; T = Circle; TRequires = boost::ext::te::v1::detail::type_list; I = DrawableT<std::cxx11::basic_stringstream >; TStorage = boost::ext::te::v1::dynamic_storage; TVtable = boost::ext::te::v1::staticvtable]’ /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp:443:74: required from ‘constexpr boost::ext::te::v1::poly<I, TStorage, TVtable>::poly(T&&) [with T = Circle; T = Circle; typename std::enable_if<(! is_samev<T, boost::ext::te::v1::poly<I, TStorage, TVtable> >), bool>::type = true; I = DrawableT<std::cxx11::basic_stringstream >; TStorage = boost::ext::te::v1::dynamic_storage; TVtable = boost::ext::te::v1::static_vtable]’ /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/test/te.cpp:493:61: required from here /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp:475:33: error: static assertion failed /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp: In instantiation of ‘constexpr boost::ext::te::v1::poly<I, TStorage, TVtable>::poly(T&&, std::indexsequence<Ns ...>) [with T = <lambda()>::<lambda(int)>; T = <lambda()>::<lambda(int)>; long unsigned int ...Ns = {}; I = Function<int(int)>; TStorage = boost::ext::te::v1::dynamic_storage; TVtable = boost::ext::te::v1::static_vtable; std::index_sequence<Ns ...> = std::integersequence]’: /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp:463:68: required from ‘constexpr boost::ext::te::v1::poly<I, TStorage, TVtable>::poly(T&&, TRequires) [with T = <lambda()>::<lambda(int)>; T = <lambda()>::<lambda(int)>; TRequires = boost::ext::te::v1::detail::type_list; I = Function<int(int)>; TStorage = boost::ext::te::v1::dynamic_storage; TVtable = boost::ext::te::v1::staticvtable]’ /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp:443:74: required from ‘constexpr boost::ext::te::v1::poly<I, TStorage, TVtable>::poly(T&&) [with T = <lambda()>::<lambda(int)>; T = <lambda()>::<lambda(int)>; typename std::enable_if<(! is_samev<T, boost::ext::te::v1::poly<I, TStorage, TVtable> >), bool>::type = true; I = Function<int(int)>; TStorage = boost::ext::te::v1::dynamic_storage; TVtable = boost::ext::te::v1::static_vtable]’ /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/test/te.cpp:541:59: required from here /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp:475:33: error: static assertion failed /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp: In instantiation of ‘constexpr boost::ext::te::v1::poly<I, TStorage, TVtable>::poly(T&&, std::indexsequence<Ns ...>) [with T = <lambda()>::<lambda(int, int)>; T = <lambda()>::<lambda(int, int)>; long unsigned int ...Ns = {}; I = Function<int(int, int)>; TStorage = boost::ext::te::v1::dynamic_storage; TVtable = boost::ext::te::v1::static_vtable; std::index_sequence<Ns ...> = std::integersequence]’: /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp:463:68: required from ‘constexpr boost::ext::te::v1::poly<I, TStorage, TVtable>::poly(T&&, TRequires) [with T = <lambda()>::<lambda(int, int)>; T = <lambda()>::<lambda(int, int)>; TRequires = boost::ext::te::v1::detail::type_list; I = Function<int(int, int)>; TStorage = boost::ext::te::v1::dynamic_storage; TVtable = boost::ext::te::v1::staticvtable]’ /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp:443:74: required from ‘constexpr boost::ext::te::v1::poly<I, TStorage, TVtable>::poly(T&&) [with T = <lambda()>::<lambda(int, int)>; T = <lambda()>::<lambda(int, int)>; typename std::enable_if<(! is_samev<T, boost::ext::te::v1::poly<I, TStorage, TVtable> >), bool>::type = true; I = Function<int(int, int)>; TStorage = boost::ext::te::v1::dynamic_storage; TVtable = boost::ext::te::v1::static_vtable]’ /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/test/te.cpp:547:75: required from here /home/ikobein/rnd/sw-engineering-rnd/boost-te-test/te/include/boost/te.hpp:475:33: error: static assertion failed make[2]: [test/CMakeFiles/te.dir/build.make:76: test/CMakeFiles/te.dir/te.cpp.o] Error 1 make[1]: [CMakeFiles/Makefile2:505: test/CMakeFiles/te.dir/all] Error 2 make: *** [Makefile:101: all] Error 2

Steps to Reproduce the Problem

Ubuntu 20.4, cmake 3.24.2, gcc 9.4.0, 10.3.0, 11.1.0 0.clone repository

  1. mkdir build: cd build; cmake ..
  2. make
pfeatherstone commented 1 year ago

This is a known issue and I'm pretty sure it's unfixable

YuraCobain commented 1 year ago

Thank you for reply. Does it impact only this specific functionality covered in example and could turn off? Is the rest of functionality stable on modern compilers?

pfeatherstone commented 1 year ago

This implementation is not guaranteed to work everywhere. It makes assumptions on the order things are compiled and analysed. By the time the compiler compiles poly, the implementation hopes the types are complete. The compiler might compile things in a different order in which case the types may not be complete by the time it gets to poly. In my opinion, you're better off taking the storages types and defining your erased types from scratch. It's not a lot of effort at all. The storage types do a lot of the heavy lifting and it will work!

pfeatherstone commented 1 year ago

We can provide some examples at some point

pfeatherstone commented 1 year ago

It's possible @krzysztof-jusiak will come up with some other implementation and make it work but it will no doubt require c++20 and likely a very modern compiler. That's not a bad thing. But using the storage types manually will work everywhere and even with c++14

YuraCobain commented 1 year ago

Thank you for detailed answer. If you provide simple example with manual storage I appreciate it.

pfeatherstone commented 1 year ago

Sure. I can't do that now. But will try to remember tomorrow

pfeatherstone commented 1 year ago

https://godbolt.org/z/W3PxoKa1f I recently submitted a PR to the dlib library which has storage policies. I put a bit more effort in that PR than i did in this one.

pfeatherstone commented 1 year ago

Yes it's a bit more manual but it works, compiles with C++14 and just as performant as libraries which implement polys, since performance bottlenecks will only ever be in the storage policies.

YuraCobain commented 1 year ago

Thanks a lot for demo. So the same approach should work smoothly with std::any to not bring dlib dependency into scene, isn't it? As I understand it's demo when project can't afford C++ higher than 14.

pfeatherstone commented 1 year ago

You can strip out the storage policies stuff from dlib. You should only need dlib/any/storage.h.

pfeatherstone commented 1 year ago

I imagine std::any uses a small buffer optimization (same as storage_sbo), or heap only (same as storage_heap). You don't get the others.

pfeatherstone commented 1 year ago

You can literally copy paste the contents of dlib/any/storage.h

pfeatherstone commented 1 year ago

But yeah you could do something similar with std::any. I like this because I can customize the SBO, create view types or shared types. It's quite flexible

krzysztof-jusiak commented 1 year ago

I've been working recently on a different project with similar approach and made it work with modern versions of gcc, clang, msvc. Will back port the solution to te but just wanted to let you know that it's possible.

pfeatherstone commented 1 year ago

Awesome ! Will it work with C++14?

pfeatherstone commented 1 year ago

https://godbolt.org/z/qe4dnM7T7 This one uses the storage policies in te instead of dlib.

pfeatherstone commented 1 year ago

I've been working recently on a different project with similar approach and made it work with modern versions of gcc, clang, msvc. Will back port the solution to te but just wanted to let you know that it's possible.

Do you have a timeline on when this will get merged. I'm super interested in this!