val - disappointed in SE
val - disappointed in SE

Reputation: 1543

Is it possible to create std::any with std::reference_wrapper from just std::any?

Let's say, I have an std::any that store type T in it. Is it possible to create another std::any that will contain type std::reference_wrapper<const T>? Like

std::any original = std::string("Test string");
std::any reference;

// Magic here

auto ref = std::any_cast<std::reference_wrapper<const std::string>>(reference); // Works

Upvotes: 1

Views: 854

Answers (3)

Oktalist
Oktalist

Reputation: 14724

If you want this badly enough, you can create a little wrapper class around a std::any that captures and type-erases the "convert to reference_wrapper" operation when it is constructed:

class any_refable
{
public:
    std::any ref() const { return converter(any); }

    const std::any& get() const& { return any; }
    const std::any&& get() const&& { return std::move(any); }
    std::any& get() & { return any; }
    std::any&& get() && { return std::move(any); }

    any_refable() = default;

    template <typename T, typename = std::enable_if_t<! std::is_same_v<std::decay_t<T>, any_refable>>>
    any_refable(T&& v) : any(std::forward<T>(v)), converter(make_converter<std::decay_t<T>>()) {}

    template <typename T, typename = std::enable_if_t<! std::is_same_v<std::decay_t<T>, any_refable>>>
    any_refable& operator=(T&& v) { any = std::forward<T>(v); converter = make_converter<std::decay_t<T>>(); return *this; }

private:
    using converter_t = std::any (*)(const std::any&);

    std::any any;
    converter_t converter = nullptr;

    template <typename T>
    static converter_t make_converter() {
        return [](const std::any& any) { return std::any(std::cref(std::any_cast<const T&>(any))); };
    }
};

DEMO

Upvotes: 1

n314159
n314159

Reputation: 5095

The following works:

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

int main() {
    std::any original = std::string("Test string");
    std::any ref = std::cref(std::any_cast<const std::string&>(original)); 

    std::any_cast<std::string&>(original)[0] = 'X';

    std::cout << std::any_cast<std::reference_wrapper<const std::string>>(ref).get() << '\n'; // Prints Xest string
}

Edit: As said in the comment, this only works if the type is known at compile time. If the type of the contained object is arbitrary, it is impossible, since the std::reference_wrapper has to be constructed at some point and for this it needs to know the type it has to wrap at compile time, there is no way around this since C++ is statically typed.

Upvotes: 0

HolyBlackCat
HolyBlackCat

Reputation: 96896

It is impossible, unless you know the exact stored type (see the other answer), or the list of possible types (in which case you can switch over original.type()).

Upvotes: 1

Related Questions