2017-09-25 14 views
3

スタックオーバーフローの誰かがラムダや関数を独自のクラスに取り込む興味深い方法を書いています。私はそれを簡素化しようとしていた、と私は近いと思ったが、いくつかの問題を抱えていた。彼らの例は:テンプレートを作成する方法可変引数を持つ関数の戻り型

// OT => Object Type 
// RT => Return Type 
// A ... => Arguments 

template<typename OT, typename RT, typename ... A> 
struct lambda_expression { 
    OT _object; 
    RT(OT::*_function)(A...)const; // A pointer to a member function, 
            // specifically the operator() 

    lambda_expression(const OT & object) // Constructor 
     : _object(object), 
      _function(&decltype(_object)::operator()) {} // Assigning the function pointer 

    RT operator() (A ... args) const { 
     return (_object.*_function)(args...); 
    } 
}; 

は、基本的にこれは、あなたが行くことができます:

int captureMe = 2; 
auto lambda = [=](int a, int b) { return a + b + captureMe;}; 
lambda_expression<decltype(lambda), int, int, int>(lambda); 

私はこれを単純化しようとすると、あなたのためlambda_expressionクラスに含まれるポインタが、必要ではないであろうと考えられていましたoperator()へのポインタを呼び出す代わりに、関数オブジェクト自体を呼び出すことができます。だから私はこれを試してみました:

template <typename OT, typename ... Args> // No Return type specified 
struct lambdaContainer 
{ 
    lambdaContainer(OT funcObj) : funcObj(funcObj){ } 
    OT funcObj; // No pointer, just the function object. 

    auto operator()(Args... args) 
    { 
     return funcObj(args...); // Call the function object directly 
    } 
}; 

次に何かのように:どうやら

auto operator()(Args... args) 
    { 
     return funcObj(args...); 
    } 

::私はラインを書いた

int captureMe = 2; 
auto lambda = [=](int a, int b) { return a + b + captureMe; }; 

lambdaContainer<decltype(lambda), int, int> lam(lambda); 

auto i = lam(1, 1); 
// i = 4; 

decltype(auto) operator()(Args... args) //works in C++14 apparently. 

をしかし、私はせずに試してみました自動キーワードと私はこれをやって惨めに失敗した私はArgs ...がどのように機能するのか理解したい。私は試しました:

decltype(funObj(Args...) operator()(Args... args) // this failed 
decltype(OT(Args...) operator() (Args... args) // this failed 
auto operator() (Args... args) -> decltype(funcObj(Args...)) // this failed 
auto operator() (Args... args) -> decltype(OT(Args...)) // this failed 

テンプレートが戻り値の型を推測できるように、Argsパラメータを拡張するにはどうすればよいですか?これは自動でのみ可能ですか?

+0

これは正しく機能しないかもしれませんが、[良いC++ブック](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list)を読むことをお勧めします。特に、いくつかの高度なもの。このような断片的な断片でC++を学ぶことは信じられないほど困難です。 –

答えて

1

decltype(e)発現eを取り、その発現の種類に評価します。私は控除の目的のために使用できるオブジェクトの「偽のインスタンス」を作成するstd::declvalを使用しています、この場合

auto operator()(Args... args) 
    -> decltype(std::declval<OT>()(std::declval<Args>()...)) 

:あなたはあなたの保存されたラムダの呼び出しを表し表現を提供する必要があります実際にはコンストラクタを呼び出すことはありません。

のは、さらにこれを打破してみましょう:

-> decltype(
    std::declval<OT>()   // create a fake instance of `OT` 
    (       // invoke it 
     std::declval<Args>()... // create a fake instance of each argument 
           // type, expanding `Args...` 
    ) 
) 

live example on wandbox

ところで

が、あなたはまだfuncObjへのお電話でのstd::forward引数がいくつか右辺値参照があるかもしれない必要があるようさらに伝播する必要がある:

auto operator()(Args... args) 
{ 
    return funcObj(std::forward<Args>(args)...); 
} 
+0

それは私が推測した最後のことです。私はdeclvalとstd :: forwardについて読んでいました。私は一種のものを得るが、他の二つは理解していない。これは、declvalがオブジェクトの「偽の」バージョンを作成していると言っているのは面白いです。 – Zebrafish

+0

@Zebrafish: 'declval'は、参照型を返します。 'std :: declval ()'は、評価されていないコンテキストの 'T {}'の代わりであるため、 "偽のインスタンスを作成する"と思っています。しかしそれはちょうど参照を返すだけです:) –

+0

@ゼブラフィッシュ:私はどんなことをさらに明確にすべきですか? –

関連する問題