2016-12-08 13 views
0

私はこのようなコードを持っている:(C++ 11では)マクロなしでこれを行うことはできますか?

void function() 
{ 
    auto isOk=task(1); 
    if(!isOk) 
    { 
     return; 
    } 

    // more code here 

    auto isOk=task(2); 
    if(!isOk) 
    { 
     return; 
    } 

    // more code here 

    auto isOk=task(3); 
    if(!isOk) 
    { 
     return; 
    } 

    // more code here 

    auto isOk=task(4); 
    if(!isOk) 
    { 
     return; 
    } 

    // more code here 

    auto isOk=task(5); 
    if(!isOk) 
    { 
     return; 
    } 

    // more code here 

    auto isOk=task(6); 
    if(!isOk) 
    { 
     return; 
    } 

    // more code here 

    auto isOk=task(7); 
    if(!isOk) 
    { 
     return; 
    } 

    // more code here 

    auto isOk=task(8); 
    if(!isOk) 
    { 
     return; 
    } 

    // more code here 

    auto isOk=task(9); 
    if(!isOk) 
    { 
     return; 
    } 
} 
私がループ内でそれらを置くことができないことに留意すべきである

(私のコードは、これに似ているがない、まさにこのコードは)

ザ・ブロックが非常にある場合醜いと私は次のようにそれを書くためにベールことがあります

#define TASK(x) {if(!task(x)) return;} 

void function() 
{ 
    TASK(1); 

    // more code here 

    TASK(2); 

    // more code here 

    TASK(3); 

    // more code here 

    TASK(4); 

    // more code here 

    TASK(5); 

    // more code here 

    TASK(6); 

    // more code here 

    TASK(7); 

    // more code here 

    TASK(8); 

    // more code here 

    TASK(9); 
} 

私の質問は次のとおりです。

は、私はC++ 11を使用していたときにこれを行うに任意のより良い方法はありますか?

このコードの問題点は次のとおりです。

簡単にデバッグできません。

マクロは名前空間内になく、他のマクロと競合する可能性があります。

アップデート1

ここでは答えのほとんどは、私は一般的な解決策を探していたときに、特定のコードで問題を解決しようとすると、私はこのコードに関連specifc質問求めています:

1 - ラムダを使ってマクロを模倣することはできますか?

2マクロを模倣するためにconstexprを使用できますか?

3私は簡単にそれらをデバッグすることができるので、(マクロと同じ結果)コンパイラフレンドリーな方法でMACROを模倣するための他の方法?私は、ベクターにところで呼び出したタスクを実行するためのコードを配置して、ループ実行します

+9

'タスク(1)&&タスク(2)&&タスクを(3)&& ...'? –

+1

ブール演算子 '&&'が短絡していることに注意してください。つまり、これらのチェーンを '&&'の大きなチェーンで連鎖させることができ、最初の関数が失敗すると、残りの関数は呼び出されません。 –

+0

@KerrekSB:それは良いですが、私はタスクを呼び出す間にいくつかのコードがあるとは言及していませんでした。私はそれを提示するためにサンプルコードを更新するつもりです。残念ながら、あなたの解決策は適切ではありません。 (これは、元の質問で説明したようにループ上に置くことができない理由です) – mans

答えて

0

:代わりに、プレーンreturnを使用しての

const size_t steps = 9; 
using ops = std::function<void()>; 
std::vector<ops> vops(steps); 
steps[0] = [] { /* some code here to execute after task 0 */ }; 
... 

for(size_t i = 0; i < steps; ++i) { 
    if(!task(i)) return; 
    if(vops[i]) (vops[i])(); 
} 
1

を、あなたは現在を残しているだけではなく、代わりに例外を使用することを選択することができます関数であるが、すべてがcatchブロックを見つけるまで機能する。このような

何か:

void tryTask(int i){ 
    auto isOk=task(i); 
    if(!isOk) 
    { 
     throw std::runtime_error("Task failed: Nr. "+to_string(i)); 
    } 
} 

function() 
{ 
    tryTask(1); 
    // more code here 
    tryTask(2); 
    // more code here 
    tryTask(3); 
    ... 
} 

これがあなたの関数が課題の一つが失敗した場合にだけ返す代わりに例外をスローすることができます。あなたはtask()機能についての制御を持っている場合は、あなたも決めるかもしれません

void callfunction(){ 
    try{ 
     function(); 
    } catch (std::exception& e) { 
     //do whatever happens if the function failed, or nothing 
    } 
} 

:これはあなたが望むものではない場合、try-catchブロックを持つ関数内またはこのような第二の機能から呼び出しのどちらか、それを囲みますboolを返す代わりに、この関数の中に例外を直接スローすることができます。

あなた自身の例外をキャッチするようにしたい場合は、例外を処理するために必要な情報のみを取る小さなクラスを作成します(必要がない場合は、空のクラスがその仕事を行います)代わりにあなたのクラスのインスタンスをスロー/キャッチします。

+1

あなたの例外の作成はコンパイルできますが、文字列の連結を意味する場合は、 – Slava

+0

@ Slavaの場合、確定した結果が得られません。固定: – Anedar

+0

タスクがfalseを返す場合、これはエラーを意味します。処理を継続して戻ってください。私が例外を使うと、コードを読んだ人は誰でもエラーではないと思うかもしれません。なぜ私は、コンパイラがプリプロセッサMACROと同じコピーを書くのを許可するが、それはcでconstexrを使ってこれを模倣することは可能ですか? ++ 11? – mans

2
void function() { 
    if (!task(1)) return; 
    // code here 
    if (!task(2)) return; 
    // more code here 
    if (!task(3)) return; 
    // more code here 
} 

これは小さくて頑丈で醜いかさばるブロックではありません。

task(1)がはるかに大きい場合は、return;を次の行に字下げすることができます。

0

ここでは、ラムダですばやく、汚いアプローチです。これを仮定し

は、あなたのタスク機能で次のように

#include <iostream> 

/** Returns 0 on success; any other returned value is a failure */ 
int task(int arg) 
{ 
    std::cout << "Called task " << arg << std::endl; 
    return arg < 3 ? 0 : 1; 
} 

はチェーンでタスクを起動します。

#include <iostream> 

int main() 
{ 
    int result = Chain::start() 
     .and_then([]() -> int {return task(1);}) 
     .and_then([]() -> int {return task(2);}) 
     .and_then([]() -> int {return task(3);}) 
     .and_then([]() -> int {return task(4);}) 
     .and_then([]() -> int {return task(5);}) 
     .and_then([]() -> int {return task(6);}) 
     .and_then([]() -> int {return task(7);}) 
     .and_then([]() -> int {return task(8);}) 
     .and_then([]() -> int {return task(9);}) 
     .result(); 
    std::cout << "Chain result: " << result << std::endl; 
    return result; 
} 

タスクが3未満引数値で呼び出された場合にのみ成功を返すので、呼び出しチェーンは3番目のステップの後で期待通りに停止します。

$ ./monad 
Called task 1 
Called task 2 
Called task 3 
Chain result: 1 

これは実装です鎖クラスのntation:

class Chain 
{ 
    public: 
     const int kSuccess = 0; 

     Chain() {_result = kSuccess;} 

     static Chain start() { return Chain(); } 

     Chain& and_then(std::function<int()> nextfn) { 
      if(_result == 0) { 
       _result = nextfn(); 
      } 
      return *this; 
     } 

     int result() { return _result; } 

    private: 
     int _result; 
}; 

私が知っている、それは醜い、それは非ジェネリックです。しかし、これがあなたが考えている一般的な方向であれば、私に知らせて、それを進化させることができます。

+0

チェーンとは何ですか?それはstlのクラスですか? – mans

+0

いいえ、答えの最後にチェーンの実装を参照してください –

0

整数シーケンスを使用できます。

// No task to call without an integer. 
bool function(std::index_sequence<>) { return true; } 

template<std::size_t I, std::size_t... S> 
bool function(std::index_sequence<I, S...>) { 
    return [](){ 
     auto isOk = task(I) 

     if (!isOk) return false; 

     // some code 

     return true; 

    // it will call function with the rest of the sequence only if the lambda return true. 
    }() && function(std::index_sequence<S...>{}); 
} 

void function() { 
    // this call with a integer sequence from 0 to 9 
    function(std::make_index_sequence<10>{}); 
} 

このコードは、手書きで書くように拡張されます。

taskのコール間のコードがステップごとに異なる場合は、タプルを使用できます。

auto afterTask = std::make_tuple(
    [](){ std::cout << "after task 0" << std::endl; }, 
    [](){ std::cout << "after task 1" << std::endl; }, 
    [](){ std::cout << "after task 2" << std::endl; }, 
    [](){ std::cout << "after task 3" << std::endl; }, 
    [](){ std::cout << "after task 4" << std::endl; }, 
    [](){ std::cout << "after task 5" << std::endl; }, 
    [](){ std::cout << "after task 6" << std::endl; }, 
    [](){ std::cout << "after task 7" << std::endl; }, 
    [](){ std::cout << "after task 8" << std::endl; }, 
    [](){ std::cout << "after task 9" << std::endl; } 
); 

し、次いでfunctionの定義変更:

template<std::size_t I, std::size_t... S> 
bool function(std::index_sequence<I, S...>) { 
    return task(I) && 
      (static_cast<void>(std::get<I>(afterTask)()), true) && 
      function(std::index_sequence<S...>{}); 
} 
関連する問題