7

後で実行できるように、一般的に関数呼び出しを「ピクル」したいと思います。これらの関数の戻りタイプは常にvoid(今のところ)になります。このようなもの:

template<typename F, typename... Args>
std::function<void()> 
pickle(F function, Args&&... args) {
    return std::bind(F, args...);
}

問題は、argsconst参照が含まれている場合std::bind、値をコピーコンストラクトしようとすることです。これは、型にコピーコンストラクターがない場合でも、常に望ましいとは限らず、有効でさえありません。std::ref左辺値参照に使用し、左辺値参照に通常を使用する方法で引数を転送するにはどうすればよいstd::forwardですか?

#include <functional>

class NonCopyable {
public:

    NonCopyable() {}

    NonCopyable(const NonCopyable&) = delete;
};

template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args)
{
    return std::bind(function, std::forward<Args>(args)...);
}

int main()
{
    NonCopyable obj;
    auto f = pickle(
        [](const NonCopyable&) {},
        obj
    );
    return 0;
}

上記のスニペットはコンパイルされず、削除されたコピーコンストラクターについて不平を言います。(誰かがそれを提案したので、私はここで前方に使用しましたが、それ以来彼らの答えを削除したようです)。

4

2 に答える 2

8

オーバーロード、イェーイ。

// also does the correct thing for `T const`
template<class T>
std::reference_wrapper<T> maybe_ref(T& v, int){ return std::ref(v); }

// just forward rvalues along
template<class T>
T&& maybe_ref(T&& v, long){ return std::forward<T>(v); }

template<typename F, typename... Args>
std::function<void()> 
pickle(F function, Args&&... args) {
    return std::bind(function, maybe_ref(std::forward<Args>(args), 0)...);
}

int/longパラメーターと引数は0、オーバーロードがあいまいであると判断したコンパイラーの左辺値の場合を明確にし、それ以外の場合は害を及ぼしません。

于 2013-03-19T14:04:55.830 に答える
0

これは少し醜いです(の使いすぎenable_if)が、機能します:

template<typename T> typename std::enable_if<
  !std::is_lvalue_reference<T>::value, T &&>::type
  forward_as_ref(typename std::remove_reference<T>::type &t) {
    return static_cast<T &&>(t);
  }
template<typename T> typename std::enable_if<
  !std::is_lvalue_reference<T>::value, T &&>::type
  forward_as_ref(typename std::remove_reference<T>::type &&t) {
    return t;
  }
template<typename T> typename std::enable_if<
  std::is_lvalue_reference<T>::value,
  std::reference_wrapper<typename std::remove_reference<T>::type>>::type
  forward_as_ref(T t) {
    return t;
  }

代わりに、クラステンプレートの特殊化を使用したバージョンを次に示します。

template<typename T> struct forward_as_ref_type {
   typedef T &&type;
};
template<typename T> struct forward_as_ref_type<T &> {
   typedef std::reference_wrapper<T> type;
};

template<typename T> typename forward_as_ref_type<T>::type forward_as_ref(
   typename std::remove_reference<T>::type &t) {
      return static_cast<typename forward_as_ref_type<T>::type>(t);
   }
template<typename T> T &&forward_as_ref(
   typename std::remove_reference<T>::type &&t) {
      return t;
   }
于 2013-03-19T14:10:07.367 に答える