10

I was trying some things and came to the following question: Is there a possibility to store references to a value in a std::any?

I tried the following approaches:

#include <any>
#include <iostream>
#include <functional>

auto func_by_pointer(std::any obj)
{
    *std::any_cast<int *>(obj) += 2;
}
auto modify_by_pointer(int &a)
{
    func_by_pointer(std::make_any<int *>(&a));
}

auto func_by_reference_wrapper(std::any obj)
{
    std::any_cast<std::reference_wrapper<int>>(obj).get() -= 2;
}
auto modify_by_reference_wrapper(int &a)
{
    func_by_reference_wrapper(std::make_any<std::reference_wrapper<int>>(a));
}

auto func_by_reference(std::any obj)
{
    std::any_cast<int &>(obj) *= 2;
}
auto modify_by_reference(int &a)
{
    func_by_reference(std::make_any<int &>(a));
}

int main()
{
    auto value = 3;
    std::cout << value << '\n';
    modify_by_pointer(value);
    std::cout << value << '\n';
    modify_by_reference_wrapper(value);
    std::cout << value << '\n';
    modify_by_reference(value);
    std::cout << value << '\n';
}

The result is the following output:

3
5
3
3

Yet, I was expecting it to be:

3
5
3
6

Thus, passing a pointer to value works fine. Passing a std::reference_wrapper to value works fine as well, but passing int& somehow doesn't work. Did I do something wrong in my code, or is it generally not possible to store references inside a std::any?

jan.sende
  • 750
  • 6
  • 23
  • 1
    By the way, didn't your compiler complain when you tried to make an `std::any` from a reference? Mine did when I tried, so I switched to pointers. (“Doc, it hurts when I do _this_.” “Then don't do _that_.”) Then looking for insight I made a search that led me here. – Craig Reynolds Sep 14 '20 at 19:31

1 Answers1

11

You cannot store references in std::any because, for a given type T, the constructor std::any(T) stores a value of type std::decay_t<T>, which removes reference qualifiers:

[any.cons]

template<class T>
  any(T&& value);
  1. Let VT be decay_­t<T>.

  2. Requires: VT shall satisfy the Cpp17CopyConstructible requirements.

  3. Effects: Constructs an object of type any that contains an object of type VT direct-initialized with std::forward<T>(value).

Holt
  • 36,600
  • 7
  • 92
  • 139
  • 1
    @jan.sende Or pointers. They're not dangerous if they don't own dynamic resources. – Cruz Jean Jun 15 '19 at 20:10
  • 2
    @CruzJean I know. Yet, I usually write my code in a fairly functional style, which affords me the luxury of mostly dropping pointers in favour of references. Thus, if possible, I avoid pointers because I don't like the mixing of `.` and `->` access... – jan.sende Jun 16 '19 at 00:38