0

I want to std::any to contain std::vector<std::unique_ptr<T>>.

class Foo {
 public:
  Foo() = default;
  ~Foo() = default;
  Foo(const Foo&) = default;
  Foo(Foo&&) = default;
  Foo& operator=(const Foo&) = default;
  Foo& operator=(Foo&&) = default;
  virtual void bar() = 0;
};

void f() {
  using std::any;
  using std::any_cast;
  using std::unique_ptr;
  using std::vector;
  using V = vector<unique_ptr<Foo>>;

  any a(V());
  V* v = any_cast<V>(&a);
}

According to the document, std::any_cast<T>(&a) seems to return V*. I think this doesn't copy the contained object. But when I tried to compile the above code, I got the following error:

/usr/include/c++/8/bits/stl_construct.h:75:7: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Foo; _Dp = std::default_delete<Foo>]’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Does it means that std::any_cast<V>(&a) requires V to be constructible? Does std::any_cast copy the contained object even when it is simply asked for a pointer? If so, why does it need to copy the content?

aaa
  • 3
  • 2
  • 5
    `a` is function that takes a `V` and returns an `any`. – molbdnilo Jun 11 '21 at 07:24
  • 2
    If you fix the declaration of `a` - `any a(V{})` - you will notice that you get an error without `any_cast`. This is because anything you put in an `any` must be copy-constructible. – molbdnilo Jun 11 '21 at 07:34
  • Relevant: [std::any for objects that can't be copy constructed](https://stackoverflow.com/q/46852168/580083) – Daniel Langr Jun 11 '21 at 07:57
  • @molbdnilo I misunderstood the problem. I fixed the declaration and removed the line in which `any_cast` is called, then I recompiled the code but still got the same error. So I see `any_cast` is not an issue. – aaa Jun 11 '21 at 08:55
  • @snbn That was exactly what molbdnilo pointed out. The problem is not with `any_cast`. The problem is that you can't put into `std::any` an object of a non-copyable type (such as `std::vector>`). – Daniel Langr Jun 11 '21 at 11:45

1 Answers1

1

std::any uses type-erasure techniques. And that means that whatever requirements are imposed on the erased type must be detected at the time when you erase the type. This is different from a template type, where it can assess the requirements when you invoke a function that actually uses those requirements.

So even if you don't do the thing that actually needs it, any still imposes those requirements.

That having been said, in this case you are doing the thing that actually needs it. Namely, any a(V());. It will copy the object into the internal storage of a. Remember: you can't do copy elision through a function parameter.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • When compiling, it is not determined whether the content of `std::any` will copyable or not, therefore `std::any` always requires its content to be copyable. Is it right? – aaa Jun 11 '21 at 14:40