Можно ли создать std :: any с std :: reference_wrapper из просто std :: any? - PullRequest
1 голос
/ 08 января 2020

Допустим, у меня есть std::any, в котором хранится тип T. Можно ли создать еще один std::any, который будет содержать тип std::reference_wrapper<const T>? Как

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

Ответы [ 3 ]

1 голос
/ 08 января 2020

Это невозможно, если вы не знаете точный сохраненный тип (см. Другой ответ) или список возможных типов (в этом случае вы можете switch сверх original.type()).

1 голос
/ 08 января 2020

Если вы хотите этого достаточно сильно, вы можете создать небольшой класс-оболочку вокруг std::any, который захватывает и стирает операцию «преобразовать в reference_wrapper», когда она создается:

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

0 голосов
/ 08 января 2020

Следующие работы:

#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
}

Редактировать: Как сказано в комментарии, это работает, только если тип известен во время компиляции. Если тип содержимого объекта является произвольным, это невозможно, поскольку std::reference_wrapper должен быть создан в какой-то момент, и для этого ему нужно знать тип, который он должен обернуть во время компиляции, нет никакого способа обойти это, так как C ++ имеет статическую типизацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...