【问题标题】:How to define new behavior for the if and else statements in C++如何在 C++ 中为 if 和 else 语句定义新的行为
【发布时间】:2018-08-29 02:29:33
【问题描述】:

我正在做的项目涉及一个类,让它成为myClass,它类似于一个集合,我需要让程序员以一种有意义的方式比较这种类型的对象。

我想做的是这样的:

myClass a, b;
...
if (a == b)
{
    //execute code where a and b are implicitly used as
    // each of a and b's elements, respectively
}

并让我的自定义 if 语句根据对元素执行的条件为 a 和 b 中的每对元素执行条件代码。

这是一个更具体的例子:

myClass a = {1, 2}, b = {2, 3};

if (a == b)
    std::cout << a << " equals " << b << std::endl;
else
    std::cout << a << " does not equal " << b << std::endl;

结果将在哪里(不一定按此顺序):

1 does not equal 2
2 equals 2
1 does not equal 3
2 does not equal 3

目前,我已经重载了比较运算符以返回一个“比较类型”,它只存储两个操作数和比较函数以进行惰性求值。有没有办法完成这种自定义 if/else 行为,以便在 if 语句接收到“比较类型”类型的参数时发生这种情况?还是只需要定义一个常规函数,它接受这种类型的对象和对二元运算符函数的引用作为条件代码?

我看到了这个问题,但在这种情况下,简单地定义转换为 bool 是行不通的。 C++ 'overloading' the if() statement

【问题讨论】:

  • stackoverflow.com/questions/10575766/… 重载 == 运算符,然后使用布尔 if/else 逻辑
  • 再读一遍。不,你不能这样做。您可能可以使用std::next_permutationboost::zip_iterator 实现类似的效果,但是,我的意思是,编写两个嵌套的for 并手动迭代会更容易(也更清晰)。
  • 在这种情况下,仅仅定义转换为 bool 是行不通的” - 为什么不呢?这正是if 语句所期望的。如果重载operator== 以返回“比较类型”而不是bool,则该类型必须可转换为bool。见What are the basic rules and idioms for operator overloading?。在内部,您可以随意比较元素,只要最终结果可以表示为bool。如果您使用的是 C++20,请查看新的 operator&lt;=&gt;,它更灵活。
  • 不,您不能更改ifelse 的含义来多次执行受控语句。你可以用不同的语法得到类似的东西,比如each_elem_if_else(a == b, [](const auto&amp; x, const auto&amp; y) { std::cout &lt;&lt; x &lt;&lt; " equals " &lt;&lt; y &lt;&lt; std::endl; }, [](const auto&amp; x, const auto&amp; y) { std::cout &lt;&lt; x &lt;&lt; " does not equal " &lt;&lt; y &lt;&lt; std::endl; });
  • @RemyLebeau 请注意,所需的结果包括执行一次 if 语句和执行 3 次 else 语句。

标签: c++ if-statement


【解决方案1】:

你可以这样接近:

myClass a = {1, 2}, b = {2, 3};

for(auto&& cmp:(a == b))
  if(cmp)
    std::cout << cmp.lhs << " equals " << cmp.rhs << std::endl;
  else
    std::cout << cmp.lhs << " does not equal " << cmp.rhs << std::endl;

只需在两个myClass 上定义operator== 即可返回一个可迭代对象。

每个可迭代元素都有一个lhs、一个rhs 和一个转换为bool 的运算符。

template<class Lhs, class Rhs=Lhs, class Cmp=std::equal<>>
struct comparison_t {
  Lhs lhs;
  Rhs rhs;
  operator bool()const{ return Cmp{}(lhs, rhs); }
};

struct myClass {
  int a, b;
  auto operator==( myClass const& lhs, myClass const& rhs ){
    std::array<comparison_t<int const&>> retval={{
      {lhs.a, rhs.a},
      {lhs.b, rhs.a},
      {lhs.a, rhs.b},
      {lhs.b, rhs.b},
    }};
    return retval;
  }
};

可能有一些错别字。

【讨论】:

  • 这非常聪明,非常感谢。不过,我能看到的唯一问题是,对于具有大量元素的 myClass 操作数,将比较扩展到 std::array 将需要大量内存。有没有办法解决这个问题?
  • @wwill 是的;查看for(:) 循环的作用。你只需要计算* 应该返回什么,++ 应该做什么以及如何处理 end 和 !=。数组解决方案只是最简单的一种。
【解决方案2】:

如果您可以摆脱 if/else 样式,则可以将 ifelse 块的主体作为 lambda 传递给辅助函数。

template<class T, class F> void compare_all(const myClass &a, const myClass &b, T fn_true, F fn_false) {
    for (const auto &ai: a.vec) {
        for (const auto &bi: b.vec) {
            if (ai == bi)
                fn_true(ai, bi);
            else
                fn_false(ai, bi);
        }
    }
}

compare_all 的前两个参数与 operator== 的参数相同。另外两个是 lambdas,用于在元素比较相等或不相等时保存要执行的操作。此处的示例假设在 myClass 类中有一个名为 vec 的容器,用于保存要比较的项目。

作为如何使用它的示例,下面是如何重写您的原始代码以使用此技术。

int main() {
    myClass a{1, 2}, b{2, 3};

    compare_all(a, b, 
        [](int a, int b) { std::cout << a << " equals " << b << std::endl; },
        [](int a, int b) { std::cout << a << " does not equal " << b << std::endl; }
    );
}

【讨论】:

  • 这与我的想法很接近,以防无法使用原生 if/else 样式。通过将bool(condition)(const myClass&amp; a, const myClass&amp; b) 参数添加到compare_all 来代替硬编码的operator==,以及使fn_false 可选,可以针对给定问题定制此答案。谢谢。
猜你喜欢
  • 2019-04-09
  • 1970-01-01
  • 2020-03-20
  • 2019-07-04
  • 1970-01-01
  • 2022-09-30
  • 2018-11-04
  • 2020-09-06
  • 1970-01-01
相关资源
最近更新 更多