`std::any_cast` returns a copy
Asked Answered
C

1

11

I was reading the documentation for std::any_cast and I find it strange that the API has the cast either return a value to the held object or a pointer to it. Why not return a reference? A copy needs to be made every time the function is called with a non pointer type argument.

I can see that the pointer version of the cast might signal intentions a bit more and might be a bit more clear but why not have the value returned be a reference like this?

template<typename ValueType>
ValueType& any_cast(any* operand);

instead of

template <typename ValueType>
ValueType* any_cast(any* operand);

Further it seems like even if you ask for a reference the cast removes the reference and returns a copy to the stored object see the explanations for the return values for function overloads 1-3 here http://en.cppreference.com/w/cpp/utility/any/any_cast

Chaldean answered 28/1, 2017 at 2:50 Comment(8)
And what if the input pointer is nullptr? It can't be dereferenced to satisfy a returned reference. I think what you are really asking about is why the overloads of any_cast that take a reference as input return a copy instead of a reference as output, isn't that right?Copyboy
any_cast gives a reference if you tell it to. This is like saying static_cast always returns a copy.Mickeymicki
The number of valid pointer values of a given type that can't be referenced depends on one's reading of the standard and that standard's evolution, but it is decidedly greater than 0 since it includes the nullpointer.Rohrer
Thinking about it, it seems utterly weird. I guess you or Someone™ will have to look up the original paper or papers, to find the rationale. It doesn't seem very practical, what with exception issue and performance.Rohrer
@RemyLebeau yes I guess so, I understand that the pointer version can be clearer but I am not sure why none of these casts don't return a referenceChaldean
@Mickeymicki the documentation states that the cast removes the reference, so if you ask for something like any_cast<Something&> you will still get a copy when you pass a reference to an std::any objectChaldean
@Curious: any_cast<Something&> will remove the reference while working on the object internally, but it still returns Something& as output.Copyboy
@RemyLebeau ah my mistake, that should have been very obvious, don't know how I missed that. Sorry!Chaldean
P
17

You can see a discussion regarding the C++ standard for this here: https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/ngSIHzM6kDQ

Note that Boost has defined any_cast this way for more than a decade, plus it matches static_cast and friends. So if you want a reference, do this:

any_cast<Foo&>(x)

The same as you'd do for the older _casts in C++.

Physicochemical answered 28/1, 2017 at 3:4 Comment(4)
Yeah but this isn't really a cast. The word "cast" here is a misnomer. It's a device to access the contained object.Rohrer
But if you take a look at the documentation here en.cppreference.com/w/cpp/utility/any/any_cast, the reference is removed, right?Chaldean
@Curious: Internally yes, but not in the output, because std::remove_reference_t is not applied to the return type. The return type is whatever you ask for in the template parameter.Copyboy
Just to sum up, with this function to access the object you have to explicitly opt in to get a reference, and otherwise, the default, you get the posssibilities of inefficiency and exception issue. With a reasonable design you would have explicitly do a copy to get a copy. So while this answer tells the facts of the situation, it doesn't answer the question, “why not have the value returned be a reference like this”. I can see no reasonable reason. The similarity to cast notation is an aesthetic issue where I absolutely don't share that silly notion of beauty-in-conformity.Rohrer

© 2022 - 2024 — McMap. All rights reserved.