【问题标题】:Passing operator as a parameter将运算符作为参数传递
【发布时间】:2010-12-25 15:06:43
【问题描述】:

我想要一个函数来评估 2 个 bool 变量(如真值表)。

例如:

自从

T | F : T

然后

myfunc('t', 'f', ||);  /*defined as: bool myfunc(char lv, char rv, ????)*/

应该return true;

如何传递第三个参数?

(我知道可以将它作为 char* 传递,但是我必须有另一个表来比较运算符字符串,然后执行我想避免的操作)

是否可以将 ^ (XOR) 或 || (OR) 或 && (AND) 等运算符传递给函数/方法?

【问题讨论】:

    标签: c++ c parameters operator-keyword


    【解决方案1】:

    声明:

    template<class Func> bool myfunc(char lv, char rv, Func func);
    

    或者如果你需要单独链接:

    bool myfunc(char lv, char rv, std::function<bool(bool,bool)> func);
    

    然后你可以调用:

    myfunc('t', 'f', std::logical_or<bool>());
    

    【讨论】:

    • 只是认为包含指向更多函数对象的链接会有所帮助,例如 std::logical_or cplusplus.com/reference/std/functional
    • @ybungalobill 我尝试将myfunc 实现为return func(int(lv), rv(lv))。但是像 myfunc('1', '3', std::plus&lt;int&gt;()); 这样调用它然后只返回 1 而不是 4。不就是这么用的吗?
    • @Patrick: myfunc 返回bool,所以它不能返回4。还有'1' == 49'3' == 51,所以我期望的答案是100 == 'd'
    【解决方案2】:

    @ybungalobill 发布了一个 C++ 正确答案,您应该坚持下去。如果你想传递运算符,函数将不起作用,但宏会起作用:

    #define MYFUNC(lv, rv, op) ....
    
    // Call it like this
    MYFUNC('t', 'f', ||);
    

    小心,macros are evil

    【讨论】:

      【解决方案3】:

      您可以做的是定义返回特定类型的代理运算符。

      namespace detail {
          class or {
              bool operator()(bool a, bool b) {
                  return a || b;
              }
          };
          class and {
              bool operator()(bool a, bool b) {
                  return a && b;
              }
          };
          // etc
          class X {
              or operator||(X x) const { return or(); }
              and operator&&(X x) const { return and(); }
          };
      };
      const detail::X boolean;
      template<typename T> bool myfunc(bool a, bool b, T t) {
           return t(a, b);
      }
      // and/or
      bool myfunc(bool a, bool b, std::function<bool (bool, bool)> func) {
          return func(a, b);
      }
      // example
      bool result = myfunc(a, b, boolean || boolean);
      

      您可以使用模板来传递复杂的逻辑表达式,如果不顾一切地链接此效果。

      此外,XOR 运算符是按位的,而不是逻辑的 - 尽管实际上没有什么区别。

      然而,在 C++0x 中存在 lambda 是有原因的,因为这种东西在 C++03 中完全不受欢迎。

      【讨论】:

      • 如果我错了,请纠正我,但不是超载 operator||operator&amp;&amp; 邪恶吗?
      • @Billy:不——为什么会这样?这与 boost::bind 中的 _1 等没有什么不同。
      • 抱歉...没有看到那些在类中:P 以为您破坏了包含&amp;&amp;|| 的每个表达式的短路语义!
      • 重载 operator||operator&amp;&amp; 是邪恶的(因为这样的重载不再是惰性的并且以未定义的顺序评估它们的参数)除非它们用于表达式模板(无关紧要),例如这种情况。
      【解决方案4】:

      在现代 C++ 中,可以使用 lambda 传递任何运算符。
      更新 1:提议的解决方案引入了 @HolyBlackCat 建议的小改进

      #include <iostream>
      
      template<class T, class F> void reveal_or(T a, T b, F f)
      {
          // using as function(a, b) instead of expression a || b is the same thing
          if ( f(a, b) ) 
              std::cout << a << " is || " << b << std::endl;
          else
              std::cout << a << " is not || " << b << std::endl;
      
      }
      
      template<class T> void reveal_or(T a, T b)
      {
          // reuse the already defined ||
          reveal_or(a, b, [](T t1, T t2) {return t1 || t2; });
      }
      

      如果 || 不用担心如何传递参数运算符已定义

      int main ()
      {
          reveal_or('1', 'a');
          return 0;
      }
      

      作为参数显式传递。我们可以传递任何东西,包括任何异国情调的废话

      int main ()
      {
          //same as above:
          reveal_or('1', 'a', [](char t1, char t2) { return t1 || t2; });
          //opposite of above
          reveal_or('1', 'a', [](char t1, char t2) { return !( t1 || t2; ) });
      
          return 0;
      }
      

      【讨论】:

      • std::function 作为默认参数可以节省输入,但与普通的 lambda 相比会产生额外的开销。我会写两个重载,一个有 3 个参数,没有默认参数,另一个有两个参数,调用第一个。
      【解决方案5】:

      很难实现。在 C++ 中,函数参数需要一个内存地址才能找到它的对象,但运算符是在编译时决定的。运算符不会是对象。所以你可以考虑使用 MACRO 来完成你的任务。

      【讨论】:

      • 这不是真的。 STL 仿函数通常不是函数指针。
      • 我认为STL functors也是一个对象,所以它也有一个内存地址发送到函数参数中。
      • 这无关紧要。您可以重载运算符并将它们传递给函数。碰巧的是,使用内置类型的预定义运算符无法做到这一点(没有充分的理由)。所以将运算符传递给函数肯定是有效的——只是在这个非常特殊的情况下(除非你使用 DeadMG 显示的技巧,那么它甚至适用于这种情况)。
      • 感谢康拉德。我不知道这个。而且我想知道:重载运算符->为运算符创建类的RTTI额外信息,因此对于编译器,它不是默认运算符(编译器使用默认二进制代码生成)。重载参数将编译以引用 RTTI 以了解操作员如何处理其操作。所以它可以通过引用,而默认运算符不能通过。对吗?(我英语不好。对不起。)
      猜你喜欢
      • 2017-11-18
      • 2018-03-27
      • 1970-01-01
      • 1970-01-01
      • 2013-06-23
      • 1970-01-01
      • 1970-01-01
      • 2014-07-24
      • 1970-01-01
      相关资源
      最近更新 更多