C++ Logo

std-proposals

Advanced search

Re: std::any / std::any_cast without typeid

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Sat, 5 Dec 2020 16:21:20 -0500
On Sat, Dec 5, 2020 at 3:49 PM connor horman via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> On Sat, Dec 5, 2020 at 14:31 Nikolay Mihaylov via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> Consider following code:
>>
>> struct A{
>> virtual ~A() = default;
>> virtual int op(int a, int b) const = 0;
>> };
>>
>> struct Sum : A{
>> int op(int a, int b) const override{
>> return a + b;
>> }
>> };
>>
>> #include <any>
>>
>> std::any x = Sum{};
>>
>> int main(){
>> return std::any_cast<A &>(x).op(5, 5);
>> }
>>
>> It crashes with `std::bad_any_cast` exception. [...]
>>
> Maybe we need some other kind of cast, for example
>> *std::non_secure_any_cast* that just casts the value no matter what.
>>
>
You need to distinguish between different kinds of "casts." Some are
physically possible to implement; some aren't.
For example, it's trivial to implement a reinterpret_any_cast<T>. But that
won't help you in situations like

struct A { int i = 1; };
struct B { int j = 2; };
struct C : A, B { int k = 3; };
std::any x = C{};
int main() { return reinterpret_any_cast<B&>(x).j; } // returns 1, not 2

It's also possible to implement a dynamic_any_cast, exploiting the special
fact that std::any always owns its contents and therefore knows (at
construction time) the *most derived type* of the contained object. For
this implementation, see the worked example in "Back to Basics: Type
Erasure" <https://www.youtube.com/watch?v=tbUCHifyT24&t=36m59s> (CppCon
2019); and for the detailed semantics of dynamic_cast and the significance
of knowing the *most derived type*, see "dynamic_cast from scratch"
<https://www.youtube.com/watch?v=QzJL-8WbpuU> (CppCon 2017). However,
dynamic_cast works only on polymorphic types.

struct A { int i = 1; };
struct B { int j = 2; virtual ~B(); };
struct C : A, B { int k = 3; };
std::any x = C{};
int main() { return dynamic_any_cast<B&>(x).j; } // OK, returns 2

However, from your motivation, it seems like you are really asking for the
ability to do, like,

std::any x = 3.14;
int main() { return static_any_cast<float>(x); } // could this return
3.14f? NO!

and that's simply physically impossible. (Again, see "Back to Basics: Type
Erasure" for the details.)

HTH,
–Arthur

Received on 2020-12-05 15:21:33