我可以在没有宏的情况下做到这一点(在C ++ 11中)吗?

时间:2016-12-08 17:30:55

标签: c++11 lambda macros c-preprocessor constexpr

我有这样的代码:

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;
    }
}

应该注意的是我不能把它们放在一个循环中(我的代码与此类似但不完全是这个代码)

if块是非常难看的,我可能很难写如下:

 #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

由于这里的大部分答案试图解决特定代码中的问题,当我在寻找通用解决方案时,我会询问与此代码相关的特定问题:

1-我可以使用lambda来模仿宏吗?

2-我可以使用constexpr来模仿宏吗?

3-以编译器友好的方式模仿MACRO的任何其他方式(与宏的结果相同)所以我可以轻松调试它们吗?

5 个答案:

答案 0 :(得分: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;放在下一行缩进上。

答案 1 :(得分:1)

您可以选择使用异常代替使用普通return,而不是只保留当前函数,而是查看所有函数,直到找到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);
    ...
}

但是,如果其中一个任务失败,这会让您的函数抛出异常而不是返回。如果这不是您想要的,请使用try-catch块将其包围在函数内部,或者从第二个函数中调用它:

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

如果你可以控制task()函数,你也可以决定直接在这个函数中抛出异常,而不是返回一个bool。

如果你想确保你只捕获自己的异常,那么为此只写一个小类,只获取处理异常所需的信息(如果你不需要,那么空类就可以完成这项工作)和抛出/捕获你的类的实例。

答案 2 :(得分:0)

我会将代码执行btw调用任务放入向量中,然后运行循环:

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])();
}

答案 3 :(得分:0)

这是一个使用lambdas的快速而肮脏的方法。

假设这是你的任务功能:

#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

这是Chain类的实现:

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;
};

我知道,它看起来很丑陋而且非通用。但如果这是你想到的大方向,请告诉我,我们可以发展它。

答案 4 :(得分:0)

您可以使用整数序列。

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...>{}); } 的定义
{{1}}