15

どうすれば次のことができるのだろうか

void f(string &&s) { 
  std::string i(move(s)); 
  /* other stuff */ 
} 

int main() { 
  std::string s; 
  bind(f, s)(); // Error.
  bind(f, move(s))(); // Error.
  bind(f, ref(s))(); // Error.
}

右辺値参照を渡して、それを右辺値参照(おそらくラップされている)として呼び出しラッパーに格納するにはどうすればよいですか?std::reference_wrapper<>に変換関数を持つようなクラスを手動で作成できることは知っていますがT&&、それを避けて標準テクノロジを使用したいと思います。


AProgrammerが推奨するように実装しました。

template<typename T> struct adv { 
  T t; 
  explicit adv(T &&t):t(forward<T>(t)) {} 
  template<typename ...U> T &&operator()(U &&...) { 
    return forward<T>(t); 
  } 
}; 

template<typename T> adv<T> make_adv(T &&t) { 
  return adv<T>{forward<T>(t)}; 
}

namespace std { 
  template<typename T> 
  struct is_bind_expression< adv<T> > : std::true_type {}; 
} 

今私は言うことができます

void f(string &&s) { 
  std::string i(move(s)); 
  /* other stuff */ 
} 

int main() { 
  std::string s; 
  bind(f, make_adv(move(s)))(); // Works!
}

左辺値をに渡すmake_advと、入力引数を参照する左辺値として転送されるためstd::ref、この場合は、の代わりに使用できます。

4

4 に答える 4

7

これについての私の見解。

N3225では20.8.10.1.2/10

バインドされた引数v1、v2、...、vNおよびそれらに対応するタイプV1、V2、...、VNの値は、バインドの呼び出しから派生したタイプTiDおよび呼び出しラッパーgのcv修飾子cvに依存します。次のように:

  • TiDがreference_wrapperの場合、引数はtid.get()であり、そのタイプViはT&です。
  • is_bind_expression :: valueの値がtrueの場合、引数はtid(std :: forward(uj)...)であり、その型Viはresult_of::typeです。
  • is_placeholder :: valueの値jがゼロでない場合、引数はstd :: forward(uj)であり、そのタイプViはUj&&;です。
  • それ以外の場合、値はtidであり、そのタイプViはTiD cv&です。

したがって、右辺値参照を持つ唯一の可能性は、is_bind_expression<TiD>::value真であるかis_placeholder<TiD>::valueゼロでないことです。2番目の可能性には望ましくない影響があり、最初の可能性で目的の結果を達成することは、標準で提供されるタイプに制限すれば、解決しようとしている問題が解決されることを意味します。したがって、唯一の可能性は、独自のラッパーと特殊is_bind_expression<TiD>化(20.8.10.1.1/1で許可されている)を提供することです。

于 2011-02-26T10:24:55.977 に答える
6

右辺値参照を渡して、それを右辺値参照として呼び出しラッパーに格納するにはどうすればよいですか?

ここでの問題は、そのようなバインド関数オブジェクトが複数回呼び出される可能性があることです。関数オブジェクトがバインドされたパラメーターを右辺値として転送した場合、これは明らかに1回だけ機能します。したがって、これは少し安全上の問題です。

しかし、場合によっては、この種の転送がまさにあなたが望むものです。ラムダを仲介として使用できます。

bind([](string& s){f(move(s));},move(s));

基本的に、「move-capture」が欠落している場合の回避策として、このbind+lambdaの組み合わせを考え出しました。

于 2011-02-26T10:45:44.733 に答える
2

この質問に出くわしたとき、私は「右辺値のreference_wrapper」をグーグルで探していました。私の答えが役立つかどうかはわかりません。std::bindとは関係がなく、実際には機能しませんが、他のユースケースでは誰かに役立つ可能性があります。

これがrvalue_reference_wrapperを実装する私の試みです:

#pragma once

#include <type_traits>
#include <memory>
#include <utility>

template<class T>
class rvalue_reference_wrapper
{
public:
    static_assert(::std::is_object<T>::value, "rvalue_reference_wrapper<T> requires T to be an object type.");

    using type = T;

    rvalue_reference_wrapper(T& ref_value) = delete;

    rvalue_reference_wrapper(T&& ref_value) noexcept
        : _pointer(::std::addressof(ref_value))
    {
    }

    operator T&&() && noexcept
    {
        return ::std::move(*_pointer);
    }

    T&& get() && noexcept
    {
        return ::std::move(*_pointer);
    }

    template<class... ArgTypes>
    auto operator()(ArgTypes&&... args) &&
        -> decltype(::std::invoke(::std::declval<rvalue_reference_wrapper<T>>().get(), ::std::forward<ArgTypes>(args)...))
    {
        return (::std::invoke(::std::move(*this).get(), ::std::forward<ArgTypes>(args)...));
    }

private:
    T* _pointer;
};

template<class T>
inline rvalue_reference_wrapper<T> rv_ref(T& ref_value) = delete;

template<class T>
inline ::std::enable_if_t<!(::std::is_lvalue_reference<T>::value), rvalue_reference_wrapper<T>> rv_ref(T&& ref_value) noexcept
{
    return rvalue_reference_wrapper<T>(::std::forward<T>(ref_value));
}

#ifdef _MSC_VER
namespace std
{
    template<class T>
    struct _Unrefwrap_helper<rvalue_reference_wrapper<T>>
    {
        using type = T &&;
        static constexpr bool _Is_refwrap = true;
    };
}
#else
#pragma error("TODO : implement...")
#endif

名前空間stdの最後の特殊化により、MSVCの標準ライブラリの実装が私のタイプで機能するようになります。たとえば、std::make_tupleを使用する場合です。

int a = 42;
auto p_int = std::make_unique<int>(42);
auto test_tuple = std::make_tuple(42, std::ref(a), rv_ref(std::move(p_int)));
static_assert(std::is_same<decltype(test_tuple), std::tuple<int, int &, std::unique_ptr<int>&&>>::value, "unexpected result");

他の標準ライブラリの実装に同様の「アンラッピング」ロジックを実装することは難しくないと思います。

于 2018-04-27T21:53:15.653 に答える
0

可変ラムダオブジェクトを使用できます。

auto func = [=]() mutable {
    f(std::move(s));
};
于 2011-02-26T10:51:59.797 に答える