-2

I am working on a C++17 project and there i am using std::any. A minimal reproducible example is given below for reference explaining what i want to achieve.

#include <any>
#include <vector>
#include <iostream>
int main()
{
    std::vector<int> vec{1,2,3};
    
    std::any anything = vec;
    
   // anything.push_back(4);//i want to add an element into vector vec, using variable anything but this statement won't work

    
    std::cout<<std::any_cast<std::vector<int>>(anything).size()<<std::endl;//prints 3 
    std::any_cast<std::vector<int>>(anything).push_back(4);//this adds(push_back) element into rvalue
    std::cout<<std::any_cast<std::vector<int>>(anything).size()<<std::endl;//prints 3 but i want 4 
}

As can be seen in the above example, i have a std::any object and i am using std::any_cast to add element into the vector. I want to add the element into the actual(lvalue) vector named vec but instead, the element is added into an rvalue. Is there a way to add element into the vector named vec using std::any. If not then is there any other way of doing this like using std::variant or something else that i may not be aware of. I am looking for a way of doing this in any version of C++ like C++11 or C++17 etc.

In my actual project, there is requirement for storing object of any type. So i got the same problem there. And then realized what is wrong(namely, we are using push_back on an rvalue) and then i reduced the problem to a minimal reproducible example and am asking here.

  • why you use `std::any`? and why you're wrapping (actually copying) a existing `vector`? – apple apple Dec 16 '21 at 15:01
  • 1
    it's OK, but why you still want to access old `vector`? – apple apple Dec 16 '21 at 15:05
  • That doesn't look like a great design to me. Maybe you should consider refactoring your project instead? – Aconcagua Dec 16 '21 at 15:36
  • Just to clarify, do you want to add an element to the vector `vec`, or the vector stored in `anything` which was copy-constructed from `vec`? You're using the two interchangeably but they are not the same object. – Useless Dec 16 '21 at 16:11
  • @Useless I want to add the element into the original vector `vec` and not in the copy that is stored inside `anything` –  Dec 16 '21 at 16:13
  • So you don't need `std::any` at all in that case. If you _do_ need `std::any` then I still don't understand your problem statement. Do you want `std::any` to store a reference to `vec` as one of the answers suggests? But if `vec` is still in scope, as in your example, you can still just append to it directly ... – Useless Dec 16 '21 at 16:16
  • @Useless Yes as i said this is just an example that i made to reproduce the problem. In this example there is no need for `std::any` i already know. I just wanted to know what i was doing wrong and was my analysis of what is going on correct or not. The answers showed me that i was wrong in my analysis and they correct/improved my understanding of `std::any` which is basically what i needed. –  Dec 16 '21 at 16:19
  • So when I asked you to clarify and you said you wanted to update the local scope vector `vec` ... that's _not_ what you really want to achieve? And if it's not, why do you keep talking about `vec` as if it's somehow relevant to your problem? This is all very confusing. – Useless Dec 16 '21 at 16:27

2 Answers2

2

we are using push_back on an rvalue

No, that's not the problem. any stores a copy of what it is given. It doesn't reference some other object. It creates an object from what it is given. So even if you get a reference to the object in the any, it wouldn't be a reference to vec itself.

If you want to store a reference to an object in an any, you need to do so explicitly by storing either a pointer or a reference_wrapper to that object:

using ref_type = decltype(std::ref(vec));

std::any anything = std::ref(vec);

std::any_cast<ref_type>(anything).get().push_back(4);

Note that having an any which references an object is dangerous. If the any outlives the lifetime of the referenced object, you'll get bad things when you try to access the referenced object. This is part of why any stores copies by default.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
1

You miss a reference:

std::any_cast<std::vector<int>&>(anything).push_back(4);
//                            ^

Currently, you create copy with the std::any_cast.

Note: As pointed by Nicol Bolas, that only avoid copy for the cast, but the copy of the initial std::vector into the std::any is not avoided.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • That will give you a reference to the object in the `any`, but not a reference to `vec`. – Nicol Bolas Dec 16 '21 at 15:11
  • There doesn't appear to be any place in the asker's code where they think they're making a reference to `vec` but aren't. After making the copy into `anything`, all subsequent code acts on `anything` and none of it acts on `vec`. – Nathan Pierson Dec 16 '21 at 15:15
  • @NicolBolas: Indeed, but not sure if it would not be sufficient for OP. – Jarod42 Dec 16 '21 at 15:15
  • 1
    @NathanPierson: "*There doesn't appear to be any place in the asker's code where they think they're making a reference to vec but aren't.*" The OP specifically says, "Is there a way to add element into the vector named vec using std::any". It's even in bold-face. The OP clearly doesn't know that `any` doesn't reference the original object by default. – Nicol Bolas Dec 16 '21 at 15:16
  • @NicolBolas Oh, yes, my bad. – Nathan Pierson Dec 16 '21 at 15:20
  • @NicolBolas You wrote *That will give you a reference to the object in the `any`, but not a reference to `vec`.* As i understand it now, we have a *reference to a vector of int* inside `std::cast_any`. And so by using this reference i can change the actual vector `vec` which is a vector of `int`. My question is why did you wrote that this gives us a reference to the object in the `any` but not a reference to `vec` since the reference is referring to the vector `vec` which is what i wanted. *Did you mean that it will give a reference to the copy of `vec` that is stored in `any`?* –  Dec 16 '21 at 15:36
  • @AanchalSharma: My change still make `anything` a copy of `vec`, but allows to modify `anything` – Jarod42 Dec 16 '21 at 15:40
  • Continued: Did you mean that it will give a reference to the copy of vec that is stored in any and not the actual vector `vec`? –  Dec 16 '21 at 15:42
  • @Jarod42 So this means that the element `4` is added to the vector stored inside `any` object instead of the actual vector `vec` right? –  Dec 16 '21 at 15:43
  • @AanchalSharma: "*Did you mean that it will give a reference to the copy of vec that is stored in any and not the actual vector vec?*" Yes, that is a rewarding of my literal words that you quoted. "object in the `any`" means exactly that. – Nicol Bolas Dec 16 '21 at 15:47
  • @AanchalSharma: yes. `vec` is unmodified with my proposal, but you got expected output as vector stored in `anything` is 4 at the end. – Jarod42 Dec 16 '21 at 15:49