是否有可能实现转发参考,如没有类型扣除的行为?

时间:2017-01-17 12:57:49

标签: c++ c++11 language-lawyer rvalue-reference perfect-forwarding

最近我了解了通用(或转发)引用。它们仅适用于模板中的类型推导或var schema = new mongoose.Schema({ razonSocial: String, cuit: String, vsat: [{ CPA: Number, IP: String, }] }); / auto

当我使用左值引用(&)时,我无法将其绑定到右值(临时)对象。当我使用rvalue-reference(&&)时,我无法将其绑定到lvalue对象。转发引用既可以使用非常量左值也可以使用右值。

是否可以在没有类型扣除的情况下实现转发参考行为?

decltype

1 个答案:

答案 0 :(得分:2)

排序。您可以键入 - 删除前向引用的概念到T

template<class T>
struct forward_ref {
  using extract_sig = T(void*);
  using get_sig = T const&(void*);

  extract_sig* extract = nullptr;
  get_sig* gettor = nullptr;

  void* pvoid;


  template<class U>
  void wrap( U&& t ) {
    auto* pt = std::addressof(t);
    using pT = decltype(pt);
    pvoid = const_cast<void*>(static_cast<void const*>(pt));
    gettor = [](void* pvoid)->T const& {
      // std::cout << "getting:\n";
      auto* pt = static_cast<pT>(pvoid);
      return *pt;
    };
    extract = [](void* pvoid)->T {
      // std::cout << "extracting via " << (std::is_rvalue_reference<U&&>::value?"move":"copy") << "\n";
      auto* pt = static_cast<pT>(pvoid);
      return std::forward<U>(*pt);
    };
  }

  forward_ref(T const& t){ wrap(t); }
  forward_ref(T && t = {}){ wrap(std::move(t)); }


  bool valid() const { return gettor&&extract; }
  operator T()&&{
    // std::cout << "operator T&&\n";
    T r = extract(pvoid);
    // std::cout << "extracted\n";
    gettor=nullptr; extract=nullptr; pvoid=nullptr;
    return r;
  }
  operator T const&() const &{
    // std::cout << "operator T const&\n";
    return gettor(pvoid);
  }
  T get()&& { return std::move(*this); }
  T const& get() const& { return *this; }
};

所以你可以这样做:

void Foo(forward_ref<std::string> s); // rvalue-reference

s的行为(有点)就像对std::string的转发引用。

如果std::move来自s,它会复制传入的std::string或从中移动,具体取决于它是否为左值或左值。

现在,这非常愚蠢,因为

void Foo(std::string s)

将会比上面那种花哨的forward_ref更好的想法。

如果移动很便宜并且您计划stprimg副本,那么按值获取几乎与转发参考一样快。

如果移动并不比复制便宜,只需按const&

极为罕见的是移动费用昂贵且复制费用更高。

转发引用很有用,因为在通用代码中,您不知道移动是否便宜。你知道具体的类型。

在任何情况下,该类型的live example都会删除前向参考号。