【问题标题】:Is it possible to create std::any with std::reference_wrapper from just std::any?是否可以仅从 std::any 使用 std::reference_wrapper 创建 std::any?
【发布时间】:2020-01-08 18:50:07
【问题描述】:

假设,我有一个 std::any,其中存储类型 T。是否可以创建另一个包含std::reference_wrapper<const T> 类型的std::any?喜欢

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

【问题讨论】:

    标签: c++ c++17 rtti stdany


    【解决方案1】:

    这是不可能的,除非您知道确切的存储类型(请参阅其他答案)或可能类型的列表(在这种情况下,您可以 switch 超过 original.type())。

    【讨论】:

      【解决方案2】:

      如果你非常想要这个,你可以围绕 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

      【讨论】:

      • 看起来很有趣。从std::ANY 派生不会提供更直观的界面吗?
      • 我在这里避免继承的原因有很多,这可能会填补另一个问题(这可能会因为过于基于意见而被关闭)。让我引用 Sutter 和 Alexandrescu 的书 C++ 编码标准 中的三个条目。第 34 条:“更喜欢组合而不是继承。继承是 C++ 中最紧密的耦合关系,仅次于友谊。”
      • 第 35 项:“避免从不是设计为基类的类继承。使用独立类作为基类是严重的设计错误。避免从具体类继承。从具有公共非虚拟析构函数有未定义行为的风险。”第 37 项:“继承是可替代性。必须履行所有基础合同。” Here 是一个示例,说明继承如何使调用未定义的行为变得过于容易。诚然,作曲也可以做到这一点,但更难偶然做到。
      【解决方案3】:

      以下作品:

      #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++ 是静态类型的。

      【讨论】:

      • 这需要你知道确切的存储类型,所以有点作弊。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-17
      • 2019-10-11
      • 1970-01-01
      • 2017-05-14
      • 1970-01-01
      • 2017-06-12
      • 1970-01-01
      相关资源
      最近更新 更多