因此,在非类型的情况下,我可以做这样的事情:

int val_to_check = 0;

int some_func(int param) {
  assert(val_to_check == 0);
  return param*param+param;
}

int main() {
  printf("Val: %i\n", some_func(rand()));
  return 0;
}

如果 val_to_check 被宣布 const 相反,可以通过编译器折叠断言。

我很好奇是否可以使用类的成员变量获得类似的常数折叠。例如,我可以做类似的事情:

class Test {
public:
  Test(int val) : val_(val) {}
  int some_func(int param) {
     assert(val_ == 0);
     return param*param+param;
   }
private:
  const int val_;
};

因此,当定义课程时,必须知道val_:a-la:

  Test my_test(0);
  printf("Val: %i\n", my_test.some_func(rand()));

(我知道这些是人为的例子)。似乎有时应该可以将断言折叠起来,但是我测试过的简单示例似乎并没有这样做。我得到的最好的是将主张代码移至函数末尾(编译W/ -O3时)

有帮助吗?

解决方案

在您提供的类示例中,编译器无法假设常数为零,因为您有两个运行时变量:

  • 您的 const int val_ 仅适用于类的每个实例,因此它永远无法优化类的功能代码,因为它必须适合每种情况。
  • 示例实例化无法提供字面常数,它提供了 rand() 这是可变的。它 可能 如果知道唯一的话,它可以将其优化 val_ 曾经向该类别的所有实例提供为零。

您是否尝试过向构造函数提供常数,以查看它是否优化了它?

其他提示

在C ++中,有一个“常数表达式”的概念(5.19)。这是一种字面的表达,仅涉及恒定表达式的算术表达,或具有恒定表达式的可变初始化的可变初始化的值。编译器能够在编译时确定这种表达式的值。

在您的情况下 val_ 不是“恒定表达式”,因为它可能具有不同的值,具体取决于其是成员的对象。对于离线版本的 some_func, ,您可能同意编译器不知道这是一个常数。对于内联版本,可以确定 val_, ,假设您还具有所有分析的所有构造函数的完整源代码。编译器是否能够进行此分析是一个实施质量问题 - 您的编译器显然无法做到。

val_是该实例的const,而不是所有实例。如果您实际上希望在所有情况下都相同,那么您可以使其成为静态常量,这将使编译器可以优化它,这实际上是您使用全局制造的const的第一个示例中发生的事情。

附带说明,您的示例可能会受到整数溢出的约束。

-O2似乎对我有用:

%cat foo.cxx

 #include <cstdio>
 #include <cstdlib>
 #include <cassert>

 class Test {
   public:
     Test(int val) : val_(val) {}
     int some_func(int param) {
       assert(val_ == 0);
       return param*param+param;
     }
   private:
     const int val_;
 };

 int main() {
   Test my_test(0);
   printf("Val: %d\n", my_test.some_func(rand()));
   return 0;
 }

 % g++ -S foo.cxx && grep assert foo.s ; echo $?
         .ascii "%s:%u: failed assertion `%s'\12\0"
 0

 % g++ -O2 -S foo.cxx && grep assert foo.s ; echo $?
 1

如果您想断言自己肯定会被折叠起来,则可能需要查找boost :: static_assert。

目前,我对设计的基本概念感到困扰:您允许班级用户提供一个值,但随后断言它必须是一个特定的值。如果只有一个值是正确的,为什么它们根本提供它?为什么不只是使用正确的价值并可以完成呢?

请记住,断言的总体想法是,其失败不应表示不正确的输入。它仅应用于向程序本身的基本问题发出信号 - 某处存在错误的逻辑或该顺序的内容。

另一方面,也许您正在处理允许不同值的情况,但是您想对一个特定值采取不同的操作(或以不同的方式实施相同的动作)。为了使断言折叠起来,显然必须是一个编译时间常数。

在这种情况下,我会考虑创建一个模板,该值作为非类型模板参数。专门针对要专门实现的值进行专门化模板。这大致赋予了您似乎想要的效果,但是强制执行该值的测试必须在编译时间而不是运行时间进行。您没有编写运行时代码并希望编译器的智能足够聪明,可以在编译时处理它,而是明确编写编译时间匹配。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top