【问题标题】:Change Operation at runtime in C++在 C++ 中运行时更改操作
【发布时间】:2018-12-18 09:10:42
【问题描述】:

我手头有一个小问题。假设有一个只有 2 个操作数的 if 条件,但我想让操作动态化。

void somFunc()
{
  if(a && b) /*1*/
  {
  }
  else if(a1 && b1) /*2*/
  {
  }
  else if(a || b) /*3*/
  {
  }
  else if(a1 || b1) /*4*/
}


基本上,1 和 3 的参数完全相同,操作不同,2 和 4 也是如此。我想将这 4 个操作减少到 2。
我想知道是否有一种方法可以使 oper 动态化。假设我们只有 2 个操作 && 和 ||
我可以以任何方式使用模板吗?
如果有人想知道我为什么需要这个,那么在一个大的 if/else 中有 n 个 if 条件。如果我以某种方式实现了这一点,我会将条件减少一半。

【问题讨论】:

  • 这里不能引入oper这样的特定关键字,但可以创建一个函数oper(),它接受两个参数并返回一个boolean。如果您想更进一步,可以将该函数作为参数提供给somFunc,使其更加通用
  • @Damien。我明白你的意思。我的问题的一些背景是,这是一个小型且受约束的规则引擎,其中规则是在外部定义的,包括操作。样本条件将是(X 存在)和(Y 不存在)。或类似 if (X exists) 或 (Y exists)。
  • @Ajit 感谢您的澄清。在这种情况下,已经提供的两个答案应该可以正常工作。

标签: c++ templates


【解决方案1】:

不确定这是否是您要求的,但您可以编写如下内容:

enum OPERATION { AND, OR }; 

bool operation(bool a, bool b,OPERATION op) {
    if (op == AND) return a && b;
    return a || b;
}    

void somFunc(OPERATION op)
{
    if(operation(a,b,op)) 
    {
    }
}

或者按照评论中的建议,将要执行的操作作为函数的参数,就像这样

template <OPERATION> 
void somFunc(OPERATION op)
{
    if(op(a,b)) 
    {
    }
}

这样称呼它

somFunc( [](bool a, bool b) { return a && b; });
somFunc( [](bool a, bool b) { return a || b; });

【讨论】:

  • 这是我想要的,但我有很多 if 条件,如果只有 1 个条件,上述解决方案是最好的。
  • @Ajit 你是什么意思?如果有多个条件,则多次调用该函数。请相应地编辑您的问题,以防您的示例未显示您实际想要做的事情
  • 稍微更改了我的代码,在代码下方添加了一行注释。
  • @Ajit 所以你用AND 作为参数调用operation 两次,用OR 调用两次。对不起,我没有看到问题
  • 啊,我现在明白了。谢谢!!
【解决方案2】:

您可以使用指向函数的指针。

#include <iostream>
#include <functional>


bool oper1(bool a, bool b) {
    return a || b;
}


bool oper2(bool a, bool b) {
    return a && b;
}

int main() {
    bool a = true, b = false;
    auto oper = oper1;
    if (oper(a, b)) {
        std::cout << "OR\n";
    }
    oper = oper2;
    if (oper(a, b)) {
        std::cout << "AND\n";
    }
}

首先定义所有条件,然后可以通过设置变量来切换条件。

您还可以使用继承和仿函数:

#include <iostream>
#include <functional>
#include <memory>

class Operator {
public:
    virtual bool eval(bool a, bool b) = 0;
};

class OrOperator : public Operator {
public:
    bool eval(bool a, bool b) {
        return a || b;
    }
};

class AndOperator : public Operator {
public:
    bool eval(bool a, bool b) {
        return a && b;
    }
};

class VariableOperator : public Operator {
public:
    VariableOperator(bool val) : val(val) {}
    bool eval(bool a, bool b) {
        return val;
    }
private:
    bool val;
};

int main() {
    bool a = true, b = false;
    std::unique_ptr<Operator> oper(new OrOperator);
    if (oper->eval(a, b)) {
        std::cout << "OR\n";
    }
    oper.reset(new AndOperator);
    if (oper->eval(a, b)) {
        std::cout << "AND\n";
    }
    oper.reset(new VariableOperator(true));
    if (oper->eval(a, b)) {
        std::cout << "VARIABLE\n";
    }
}

【讨论】:

  • 这种方法看起来也不错。我正在评估是否可以使用它。会在这里更新。谢谢
【解决方案3】:

您可能正在寻找这样的东西:

void somFunc()
{
  std::vector< std::function< bool(bool, bool) > > operators = {
    [](bool a, bool b){ return a && b; },
    [](bool a, bool b){ return a || b; }
  };
  for ( auto& op : operators )
  {
      if ( op( a, b ) )
      {
      }
      else if ( op( a1, b1 ) )
      {
      }
  }
}

您可以轻松地添加更多运算符或更改参数类型。

【讨论】:

    【解决方案4】:

    您也可以使用 CRTP 做到这一点:

    #include <iostream>
    #include <string>
    #include <memory>
    
    template<class T>
    class Operation
    {
    public:
       bool eval(bool a, bool b)
       {
          return this->impl().eval(a,b);
       }
    private:
       T& impl() { return static_cast<T&>(*this); }
    };
    
    class AndOperation : public Operation<AndOperation>
    {
    public:
       bool eval(bool a, bool b)
       {
          return a && b;
       }
    };
    
    class OrOperation : public Operation<OrOperation>
    {
    public:
       bool eval(bool a, bool b)
       {
          return a || b;
       }
    };
    
    int main()
    {
      AndOperation andOp;
      auto anonOp = std::make_unique<OrOperation>();
      std::cout << andOp.eval(true, true) << std::endl;
      std::cout << anonOp->eval(false,false);
    }
    

    live example here

    CRTP相对于虚拟继承有什么优势? CRTP 是静态多态 的一个例子。以下是一些参考资料:

    Compile time vs run time polymorphism in C++ advantages/disadvantages

    What is the motivation behind static polymorphism in C++?

    C++: How is this technique of compile-time polymorphism called and what are the pros and cons?

    The cost of dynamic (virtual calls) vs. static (CRTP) dispatch in C++

    【讨论】:

    • CRTP 与简单继承相比有哪些优势?
    • 是否可以使OrOperation::evalImpl受保护?
    • @ThomasSablik 你说得很对。我将使用更正确的实现来编辑答案,这也可以解决您的问题
    • 这不是批评。我喜欢你的回答,我很感兴趣。
    • @ThomasSablik 我知道这一点,但你让我注意到我犯了一个小错误,我会纠正它。这也是一种提升自己的方式
    【解决方案5】:

    可以将somFunc() 设为模板,并接受任何接受两个参数并返回可使用if 测试的值的函数。

     #include <functional>    // for binary operations in std
    
     template<class Operation> void somfunc(Operation oper)
     {
          if (oper(a,b))
          {
                // whatever
          }
     }
    
     int main()
     {
          somFunc(std::logical_and<int>());
          somFunc(std::logical_or<int>());
          somFunc(std::plus<int>());         //  addition
    
           //   pass a lambda
    
          somFunc([](int a, int b) -> int {return a + b;});   // lambda form of addition
     }
    

    在上面,我假设变量 ab(已在问题中使用,但未指定类型)的类型为 int

    【讨论】:

      猜你喜欢
      • 2017-10-30
      • 2011-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 2012-09-16
      • 1970-01-01
      相关资源
      最近更新 更多