【问题标题】:Is it possible to define a variable in expression in C++?是否可以在 C++ 中的表达式中定义变量?
【发布时间】:2009-10-02 22:49:41
【问题描述】:

我有这个疯狂的作业,我必须创建一个表达式来验证与儒略历和公历以及许多其他事物相关的日期......

问题是它必须在一个表达式中,所以我不能使用任何;

有没有在表达式中定义变量的选项?类似的东西

d < 31 && (bool leapyear = y % 4 == 0) || (leapyear ? d % 2 : 3) ....

我可以在哪里定义和初始化一个或多个变量并在该表达式中使用它们而不使用任何;

编辑:明确表示,它必须是单行表达式。没有功能..

我现在的做法是编写宏并扩展它们,所以我最终得到了这样的东西

#define isJulian(d, m, y) (y < 1751 || (y == 1752 && (m < 9) || (m == 9 && d <= 2)))
#define isJulianLoopYear(y) (y % 4 == 0)
#define isGregorian(d, m, y) (y > 1573 || (y == 1752 && (m > 9) || (m == 9 && d > 13)))
#define isGregorianLoopYear(y) ((y % 4 == 0) || (y % 400 = 0))
// etc etc ....

看来这是解决问题的唯一合适方法

编辑:这是原始问题

假设我们有变量 d my 包含日、月和年。任务是编写一个表达式来决定日期是否有效。如果日期有效,则值应为真(非零值),如果日期无效,则应为假(零)。

这是一个表达式示例(正确的表达式应该是这样的):

d + 4 == y ^ 85 ? ~m : d * (y-2)

这些是错误答案的例子(不是表达式):

if ( log ( d ) == 1752 ) m = 1;

或:

for ( i = 0; i < 32; i ++ ) m = m / 2;

仅提交仅包含一个表达式的文件,最后没有;。不要提交命令或整个程序。

  • 2.9.1752 之前是儒略历,之后是公历
  • 在儒略历中,闰年每年可被 4 整除。
  • 在公历中,每年是闰年,可以被 4 整除,但不能被 100 整除。可以被 400 整除的年份是另一个例外,是闰年。
  • 1800, 1801, 1802, 1803, 1805, 1806, ....,1899, 1900, 1901, ... ,2100, ..., 2200 不是循环年份。
  • 1896, 1904, 1908, ..., 1996, 2000, 2004, ..., 2396,..., 2396, 2400 是循环年份
  • 1752 年 9 月是另一个例外,当 2.9.1752 之后是 14.9.1752 时,因此日期 3.9.1752、4.9.1752、...、13.9.1752 无效。

【问题讨论】:

  • 使用宏然后提交预处理的表达式?另请注意,闰年规则比这更复杂。那么,这样的作业到底有什么意义呢?你确定它不应该是一个函数,而不是表达式?
  • 闰年规则可能更复杂,但边缘情况要到 2400 年才会出现,所以我认为忽略它是安全的。
  • @UncleBens:是的,宏是我迄今为止提出的唯一解决方案......它必须是一个计算结果为真/假的单行表达式。老实说,所有的作业都这么愚蠢..
  • @Max Lybbert:更复杂,因为儒略历和公历(3.9.1752、4.9.1752、...、13.9.1752)之间的日期无效(它们不存在)在其中任何一个中)。
  • 如果在 2 年或 3 年内只问作业就好了。Lambdas 会很好:)

标签: c++ inline expression


【解决方案1】:
((m >0)&&(m<13)&&(d>0)&&(d<32)&&(y!=0)&&(((d==31)&&
((m==1)||(m==3)||(m==5)||(m==7)||(m==8)||(m==10)||(m==12)))
||((d<31)&&((m!=2)||(d<29)))||((d==29)&&(m==2)&&((y<=1752)?((y%4)==0):
((((y%4)==0)&&((y%100)!=0))
||((y%400)==0)))))&&(((y==1752)&&(m==9))?((d<3)||(d>13)):true))

【讨论】:

    【解决方案2】:

    &lt;evil&gt; 如果您可以重用现有的,为什么要定义一个新的? errno 是一个完美的临时变量。 &lt;/evil&gt;

    【讨论】:

      【解决方案3】:

      我认为作业的目的是要求您在不使用变量的情况下执行此操作,而您尝试做的事情可能会违背其目的。

      【讨论】:

      • 可能是为了使用合适的库?
      • 如果这是意图,那么作业应该要求这样做。
      【解决方案4】:

      在标准 C++ 中,这是不可能的。 G++ 有一个名为statement expressions 的扩展可以做到这一点。

      【讨论】:

        【解决方案5】:

        我不相信你可以,但即使你可以,它也只能在括号内定义它们(在你的例子中),并且不能在它们之外使用。

        【讨论】:

          【解决方案6】:

          您的解决方案(我不会完全为您提供)可能会遵循以下思路:

          isJulian ? isJulianLeapyear : isGregorianLeapyear
          

          为了更具体,可能是这样的:

          isJulian ? (year % 4) == 0 : ((year % 4) == 0 || (year % 400) == 0) 
          

          您必须确保您的算法是正确的。我不是日历专家,所以我不会知道。

          【讨论】:

            【解决方案7】:

            首先:不要。它可能很可爱,但即使有一个允许它的扩展,代码高尔夫也是一种危险的游戏,它几乎总是会导致比它解决的更多的悲伤。

            好的,回到作业定义的“真正”问题。你能做额外的功能吗?如果是这样,不要在变量中捕获它是否是闰年,而是创建一个返回正确值的函数 isLeapYear(int year)。

            是的,这意味着您将多次计算它。如果这最终成为一个性能问题,我会感到非常惊讶......而且首先担心这个问题还为时过早。

            如果您不被允许编写函数作为这样做的一部分,我会感到非常惊讶。这似乎是这样一个练习的一半。

            ......

            好的,下面是您需要做的快速概述。

            首先,基本验证 - 月、日、年都是可能的值 - 月 0-11(假设从 0 开始)、天 0-30、非负年(假设这是一个约束)。

            一旦你过去了,我可能会检查 1752 的特殊情况。

            如果这无关紧要,“常规”月份可以很简单地处理。

            这给我们留下了闰年的情况,它可以分解为两个表达式 - 某事是否是闰年(将另外根据 gregorian/julian 进行分解),以及该日期在该点是否有效.

            因此,在最高级别,您的表达式看起来像这样:

            areWithinRange(d,m,y) && pass1752SpecialCases(d,m,y) && pass30DayMonths(d,m,y) && pass31DayMonths(d,m,y) && passFebruaryChecks(d,m,y)

            如果我们假设我们仅在我们主动检测到规则违规的情况下从子表达式中返回 false(6 月的 31 天,对于 30DayMonth 规则返回 false,但 2 月的 30 天是无关紧要的,并且所以通过了true),那么我们几乎可以说该级别的逻辑是正确的。

            此时,我将为各个部分编写单独的函数(作为纯表达式,单个 return ... 语句)。一旦你得到了这些,你可以用扩展版本替换顶级表达式中的方法调用。只需确保将所有内容都用括号括起来(这是一个词吗?)。

            我还会制作一个使用该表达式并具有许多有效和无效输入的测试工具程序,并验证您是否在做正确的事情。您可以通过执行以下操作将其编写在一个函数中,以便在最终上交时轻松剪切和粘贴:

            bool isValidDate(int d, int m, int y)
            {
                return
                    // your expression here
            }
            

            由于表达式会单独一行,所以很容易剪切和粘贴。

            您可能会找到其他方法来简化您的逻辑 - 例如,除了 1752 个特殊情况之外,1 到 28 天之间的日期始终有效。

            【讨论】:

            • 其实我不会写任何函数。明确表示只能提交一行表达式
            • 这很令人惊讶,但我猜这是通过在函数访问中隐藏状态来防止“作弊”。尽管如此,宏观解决方案可能被认为等同于函数。我认为您将不得不经常使用 ?: 运算符,并接受可能存在一些冗余代码的事实。学习把这样的东西作为表达式做是一个很好的练习,因为除了方便之外,没有理由将状态添加到这样的“纯函数”中。这种表达的预期输入和输出是什么?
            • @kyoryu:我使用宏只是为了让代码可读,因为它最终会出现很多 ?: 运算符,预期输入是三个“变量”dmy,输出应该是真/假跨度>
            • 这是你的作业 :) 我只是建议如果老师不想要 isJulian(),他们可能不在乎它是宏还是函数。再次 - 预期的输入和输出是什么?我也许可以提供更多帮助。问题的实际文本也可能有用。
            【解决方案8】:

            考虑到这是家庭作业,我认为最好的建议是找到自己的解决方案。

            如果我要完成这项任务,我会从打破规则开始。

            1. 我会编写一个 c++ 函数,给定变量 d、m 和 y,返回一个关于日期有效性的布尔结果。我会根据需要使用尽可能多的非递归辅助函数,并且可以随意使用 if、else if 和 else,但不要大声循环。

            2. 然后我会内联所有辅助函数

            3. 我会将所有 if、else if 和 else 语句简化为 ? : 符号

            如果我成功地限制了我对变量的使用,我也许可以将所有这些简化为一个没有变量的函数——它的主体将包含我寻找的单个表达式。

            祝你好运。

            【讨论】:

              【解决方案9】:

              您显然必须以某种方式传递日期。除此之外,您真正要做的就是链接&amp;&amp;||(假设我们将日期作为tm 结构获取):

              #include <ctime>
              bool validate(tm date)
              {
                   return (
                           // sanity check that all values are positive
                           date.tm_mday >= 1 && date.tm_mon >= 0 && date.tm_year >= 0
                           // check for valid days
                           && ((date.tm_mon == 0 && date.tm_mday <= 31)
                            || (date.tm_mon == 1 && date.tm_mday <= (date.tm_year % 4 ? 28 : 29))
                            || (date.tm_mon == 2 && date.tm_mday <= 31)
                           // yadda yadda for the other months
                            || (date.tm_mon == 11 && date.tm_mday <= 31))
                           );
              }
              

              date.tm_year % 4 ? 28 : 29 周围的括号实际上是不需要的,但为了便于阅读,我将它们包括在内。


              更新

              查看评论时,您还需要类似的规则来验证公历中不存在的日期。

              更新二

              由于您处理的是过去的日期,因此您需要实施更正确的闰年测试。但是,我通常处理未来的日期,这个错误的闰年测试将在 2012、2016、2020、2024、2028、2032、2036、2040、2044、2048、2052、2056、2060、2064、 2068, 2072, 2076, 2080, 2084, 2088, 2092, 和 2096。我预测,在这个测试失败之前,2100 台基于硅的计算机将被遗忘。我严重怀疑我们是否会在那时使用的量子计算机上使用 C++。另外,我不会是被指派去修复这个bug的程序员。

              【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-09-27
              • 1970-01-01
              • 1970-01-01
              • 2015-04-20
              相关资源
              最近更新 更多