Date: Sat, 23 Sep 2023 14:23:36 +0200
sob., 23 wrz 2023 o 13:44 Andrey Semashev via Std-Proposals
<std-proposals_at_[hidden]> napisaĆ(a):
>
> On September 23, 2023 2:08:54 PM Frederick Virchanza Gotham via
> Std-Proposals <std-proposals_at_[hidden]> wrote:
>
> > Eight months ago I suggested on the mailing list here that Runtime
> > Type Identification (RTTI) should be available inside a 'catch(...)'
> > block, as I described in this paper:
> >
> > http://www.virjacode.com/download/RTTI_current_exception_latest.pdf
> >
> > Following on from that, I would like to propose the new idea of a
> > 'template catch block'. Currently with C++23, we write try-catch as
> > follows:
> >
> > try
> > {
> >
> > }
> > catch(std::exception const &e)
> > {
> >
> > }
> > catch(...)
> > {
> >
> > }
> >
> > I propose that we can stick another catch-block between those two, as follows:
> >
> > try
> > {
> >
> > }
> > catch(std::exception const &e)
> > {
> >
> > }
> > template<typename T>
> > catch(T &obj)
> > {
> > T tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(...)
> > {
> >
> > }
> >
> > Inside the second-last catch-block, the compiler has the RTTI of the
> > thrown object at runtime, but at compile-time it has nothing. And so
> > the only way the compiler could possibly implement the second-last
> > catch-block as machine code would be to implement it in machine code
> > for every intrinsic type, as well as for every user-defined type that
> > has been seen so far in the translation unit, almost as though it had
> > been written:
> >
> > try
> > {
> >
> > }
> > catch(std::exception const &e)
> > {
> >
> > }
> > catch(char &e)
> > {
> > char tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(char signed &e)
> > {
> > char signed tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(char unsigned &e)
> > {
> > char unsigned tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(short &e)
> > {
> > short tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(short unsigned &e)
> > {
> > short unsigned tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(int &e)
> > {
> > int tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(unsigned &e)
> > {
> > unsigned tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(long &e)
> > {
> > long tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(long unsigned &e)
> > {
> > long unsigned tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > // ......... and on and on and on for every type
> > catch(...)
> > {
> >
> > }
> >
> > If the catch-block were to fail to compile for any given type, then
> > that implementation of the catch-block would be discarded (and so
> > instead it will enter the 'catch(...)' block below it).
> >
> > Of course one of the drawbacks of this new proposed feature would be
> > the bloat in size of machine code, but nowadays we have gigs of RAM
> > and terras of disk space so it's not a big deal. This bloat in machine
> > code size could be lessened by discarding the implementations that are
> > identical -- for example on most computers the machine code
> > implementations for 'signed long' and 'unsigned long' will be exactly
> > the same (depending of course on a few things such as whether
> > 'SomeFunc' is expanded inline and if the inline expansion is exactly
> > the same for both types).
> >
> > Perhaps we could also put constraints on the catch-block:
> >
> > template<typename T>
> > requires std::is_polymorphic_v<T>
> > catch (T &obj)
> > {
> > T tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> >
> > If you were to ask me how this new feature would be useful, well
> > here's one simple example:
> >
> > template<typename T>
> > catch(T &obj)
> > {
> > cout << obj << endl;
> > }
> >
> > Compiler vendors who implement this new feature could also use the
> > same implementation to write an "std::visit" that can work with an
> > "std::any" object, as follows:
> >
> > #include <any> // any
> > #include <iostream> // cout, endl
> > #include <vector> // vector
> >
> > using std::cout, std::endl;
> >
> > int main(void)
> > {
> > std::vector<std::any> vec = {1, 3.14, "hello"};
> >
> > for ( auto &e : vec )
> > {
> > std::visit([](auto &&arg){ cout << arg << endl; }, e);
> > }
> >
> > return 0;
> > }
> >
> > This new feature I'm proposing has many advantages, and only two disadvantages:
> > (1) Bloat in size of machine code
> > (2) Increase in compilation time
> >
> > Both of these disadvantages are mitigated on modern PC's with gigs of
> > RAM and terras of space.
>
> This is insane, you have no idea what you're talking about. No gigs of RAM
> will save you in a moderately sized project with thousands of types, let
> alone something like Chromium. Don't even get me started about how the
> compiler is supposed to know every type in the program.
>
>
Could the memory limit for this be infinite?
```
template<int I>
struct infinity
{
using infinity_plus_one = infinity<I + 1>;
};
int main()
{
infinity<0>::infinity_plus_one::infinity_plus_one foo;
}
```
How deep should the compiler go?
Or how many nested `std::optional<std::optional<int>>` should be supported?
Even if we limit to instantiated types, then what translation unit
should be considered?
If we consider only current translation unit then we still have infinite loop:
```
template<typename T>
class Foo { T i[2]; };
template<typename T>
void SomeFunction(T& t)
{
Foo<T> foo { t, t };
if (rand()) throw foo;
}
int main()
{
try
{
throw int{1};
}
template<T>
catch(T &e)
{
SomeFunc(e);
}
}
```
We have instantiation loop `int -> Foo<int> -> Foo<Foo<int>> ->
Foo<Foo<Foo<int>>> -> ...`
And each nested `Foo` has 2 times bigger size.
Even still people complain about overhead RTTI and Exceptions,
suggesting adding even MORE blot (RTTI * Exceptions times bigger) is DOA.
This would have one benefit, this would make RTTI and Exceptions a lot
worse that
99.99% of projects would permanently ban both
and every one would use the same "flavor" of C++ without them.
>
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
<std-proposals_at_[hidden]> napisaĆ(a):
>
> On September 23, 2023 2:08:54 PM Frederick Virchanza Gotham via
> Std-Proposals <std-proposals_at_[hidden]> wrote:
>
> > Eight months ago I suggested on the mailing list here that Runtime
> > Type Identification (RTTI) should be available inside a 'catch(...)'
> > block, as I described in this paper:
> >
> > http://www.virjacode.com/download/RTTI_current_exception_latest.pdf
> >
> > Following on from that, I would like to propose the new idea of a
> > 'template catch block'. Currently with C++23, we write try-catch as
> > follows:
> >
> > try
> > {
> >
> > }
> > catch(std::exception const &e)
> > {
> >
> > }
> > catch(...)
> > {
> >
> > }
> >
> > I propose that we can stick another catch-block between those two, as follows:
> >
> > try
> > {
> >
> > }
> > catch(std::exception const &e)
> > {
> >
> > }
> > template<typename T>
> > catch(T &obj)
> > {
> > T tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(...)
> > {
> >
> > }
> >
> > Inside the second-last catch-block, the compiler has the RTTI of the
> > thrown object at runtime, but at compile-time it has nothing. And so
> > the only way the compiler could possibly implement the second-last
> > catch-block as machine code would be to implement it in machine code
> > for every intrinsic type, as well as for every user-defined type that
> > has been seen so far in the translation unit, almost as though it had
> > been written:
> >
> > try
> > {
> >
> > }
> > catch(std::exception const &e)
> > {
> >
> > }
> > catch(char &e)
> > {
> > char tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(char signed &e)
> > {
> > char signed tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(char unsigned &e)
> > {
> > char unsigned tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(short &e)
> > {
> > short tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(short unsigned &e)
> > {
> > short unsigned tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(int &e)
> > {
> > int tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(unsigned &e)
> > {
> > unsigned tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(long &e)
> > {
> > long tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > catch(long unsigned &e)
> > {
> > long unsigned tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> > // ......... and on and on and on for every type
> > catch(...)
> > {
> >
> > }
> >
> > If the catch-block were to fail to compile for any given type, then
> > that implementation of the catch-block would be discarded (and so
> > instead it will enter the 'catch(...)' block below it).
> >
> > Of course one of the drawbacks of this new proposed feature would be
> > the bloat in size of machine code, but nowadays we have gigs of RAM
> > and terras of disk space so it's not a big deal. This bloat in machine
> > code size could be lessened by discarding the implementations that are
> > identical -- for example on most computers the machine code
> > implementations for 'signed long' and 'unsigned long' will be exactly
> > the same (depending of course on a few things such as whether
> > 'SomeFunc' is expanded inline and if the inline expansion is exactly
> > the same for both types).
> >
> > Perhaps we could also put constraints on the catch-block:
> >
> > template<typename T>
> > requires std::is_polymorphic_v<T>
> > catch (T &obj)
> > {
> > T tmp{};
> > ++tmp;
> > obj += tmp;
> > SomeFunc(obj);
> > }
> >
> > If you were to ask me how this new feature would be useful, well
> > here's one simple example:
> >
> > template<typename T>
> > catch(T &obj)
> > {
> > cout << obj << endl;
> > }
> >
> > Compiler vendors who implement this new feature could also use the
> > same implementation to write an "std::visit" that can work with an
> > "std::any" object, as follows:
> >
> > #include <any> // any
> > #include <iostream> // cout, endl
> > #include <vector> // vector
> >
> > using std::cout, std::endl;
> >
> > int main(void)
> > {
> > std::vector<std::any> vec = {1, 3.14, "hello"};
> >
> > for ( auto &e : vec )
> > {
> > std::visit([](auto &&arg){ cout << arg << endl; }, e);
> > }
> >
> > return 0;
> > }
> >
> > This new feature I'm proposing has many advantages, and only two disadvantages:
> > (1) Bloat in size of machine code
> > (2) Increase in compilation time
> >
> > Both of these disadvantages are mitigated on modern PC's with gigs of
> > RAM and terras of space.
>
> This is insane, you have no idea what you're talking about. No gigs of RAM
> will save you in a moderately sized project with thousands of types, let
> alone something like Chromium. Don't even get me started about how the
> compiler is supposed to know every type in the program.
>
>
Could the memory limit for this be infinite?
```
template<int I>
struct infinity
{
using infinity_plus_one = infinity<I + 1>;
};
int main()
{
infinity<0>::infinity_plus_one::infinity_plus_one foo;
}
```
How deep should the compiler go?
Or how many nested `std::optional<std::optional<int>>` should be supported?
Even if we limit to instantiated types, then what translation unit
should be considered?
If we consider only current translation unit then we still have infinite loop:
```
template<typename T>
class Foo { T i[2]; };
template<typename T>
void SomeFunction(T& t)
{
Foo<T> foo { t, t };
if (rand()) throw foo;
}
int main()
{
try
{
throw int{1};
}
template<T>
catch(T &e)
{
SomeFunc(e);
}
}
```
We have instantiation loop `int -> Foo<int> -> Foo<Foo<int>> ->
Foo<Foo<Foo<int>>> -> ...`
And each nested `Foo` has 2 times bigger size.
Even still people complain about overhead RTTI and Exceptions,
suggesting adding even MORE blot (RTTI * Exceptions times bigger) is DOA.
This would have one benefit, this would make RTTI and Exceptions a lot
worse that
99.99% of projects would permanently ban both
and every one would use the same "flavor" of C++ without them.
>
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
Received on 2023-09-23 12:23:48