C++ 在C+中假装静态+;

C++ 在C+中假装静态+;,c++,optimization,if-statement,static,static-if,C++,Optimization,If Statement,Static,Static If,我正在测试各种优化的组合,对于这些,我需要一个静态if,如中所述,以启用和禁用特定优化。if(const expr)并不总是有效,因为某些优化涉及更改数据布局,而这不能在函数范围内完成 基本上我想要的是: template<bool enable_optimization> class Algo{ struct Foo{ int a; if(enable_optimization){ int b; } void bar(){

我正在测试各种优化的组合,对于这些,我需要一个静态if,如中所述,以启用和禁用特定优化。if(const expr)并不总是有效,因为某些优化涉及更改数据布局,而这不能在函数范围内完成

基本上我想要的是:

template<bool enable_optimization>
class Algo{
  struct Foo{
    int a;
    if(enable_optimization){
      int b;
    }

    void bar(){
      if(enable_optimization){
        b = 0;
      }
    }
  };
};
文件c.h

template<>
class Algo<ENABLE_OPTIMIZATION>{
  struct Foo{
    int a;
    #if ENABLE_OPTIMIZATION
    int b;
    #endif

    void bar(){
      #if ENABLE_OPTIMIZATION
      b = 0;
      #endif
    }
  };
};
模板
类算法{
结构Foo{
INTA;
#如果启用"优化",
int b;
#恩迪夫
空条(){
#如果启用"优化",
b=0;
#恩迪夫
}
};
};
有人知道更好的方法吗?理论上,它可以通过使用模板元编程来完成,首先我使用了它。至少我使用它的方式是一种痛苦,导致完全无法阅读和臃肿的代码。使用上面的黑客可以显著提高生产率


编辑:我有几个优化标志,它们相互作用。

没有理由使用模板使代码变得更复杂:

template<bool enable_optimization>
  class FooOptimized
  {
  protected:
    int b;
    void bar_optim()
    {
      b = 0;
    }
  };

template<>
  class FooOptimized<false>
  {
  protected:
    void bar_optim() { }
  };

template<bool enable_optimization>
  struct Algo
  {
    struct Foo : FooOptimized<enable_optimization>
    {
      int a;

      void bar()
      {
        this->bar_optim();
      }
    };
  };

您必须对其进行分析和测试,以确定虚拟函数的开销是否比不依赖于模板参数的
Algo
Algo::Foo
中的代码复制要小。

注意:目前,这种方法不起作用,因为如果不为一个类中的某个成员分配空间,似乎就无法在该类中拥有该成员。如果您对如何使其工作有想法,请随意编辑。

你可以用这样一个成语:

template<bool optimized, typename T> struct dbg_obj {
  struct type {
    // dummy operations so your code will compile using this type instead of T
    template<typename U> type& operator=(const U&) { return *this; }
    operator T&() { return *static_cast<T*>(0); /* this should never be executed! */ }
  };
};
template<typename T> struct dbg_obj<false, T> {
  typedef T type;
};

template<bool enable_optimization>
class Algo{
  struct Foo{
    int a;
    typename dbg_obj<enable_optimization, int>::type b;

    void bar(){
      if(enable_optimization){
        b = 0;
      }
    }
  };
};
模板结构dbg_obj{
结构类型{
//伪操作,因此您的代码将使用此类型而不是T编译
模板类型&运算符=(常量U&){return*this;}
运算符T&({return*static_cast(0);/*永远不应执行此操作!*/}
};
};
模板结构dbg_obj{
T型;
};
模板
类算法{
结构Foo{
INTA;
类型名称dbg_obj::类型b;
空条(){
如果(启用_优化){
b=0;
}
}
};
};
如果禁用优化,这将为您提供一个正常的
int
成员。如果启用了优化,则
b
的类型是没有成员的结构,不会占用任何空间


由于您的方法
bar
使用运行时
if
来决定是否访问
b
,与模板专门化等明确的编译时机制相反,您在
b
上使用的所有操作也必须从虚拟结构中可用。即使相关的部分永远不会被执行,并且编译器很可能会对它们进行优化,正确性检查也是第一位的。因此,必须为替换类型编译行
b=0
。这就是虚拟赋值和虚拟强制转换操作的原因。尽管这两种方法都可以满足您的代码,但我将它们都包括在内,以防它们在其他方面被证明有用,并让您了解如何在需要它们时添加更多内容。

Jonathan Wakely提出的静态解决方案(而非动态解决方案)是一条可行之路

想法很简单:

  • 将“特定”数据隔离到其自己的类中(相应地模板化和专门化)
  • 对该数据的所有访问都完全移交给专门类(接口必须统一)
  • 然后,为了不产生空间开销,您可以通过继承这个特殊类的任何一个专门化来使用EBO(空基优化)

    注意:属性需要占用至少1字节的空间,基类在某些情况下不可用(例如为空)

    就你而言:

    • b
      是具体的数据
    • 有一个涉及它的单一操作(包括设置它的值)
    因此,我们可以轻松构建一个类:

    template <typename T> struct FooDependent;
    
    template <>
    struct FooDependent<true> {
        int b;
        void set(int x) { b = x; }
    };
    
    template <>
    struct FooDependent<false> {
        void set(int) {}
    };
    

    注意:在模板化代码中使用
    来访问基类成员,否则好的编译器将拒绝您的代码。

    预处理器开关听起来不像是一个糟糕的黑客。@zneak,这取决于条件编译对代码的影响程度,如果预处理器启用/禁用了大量块,
    bar
    的实现可能会变得更难阅读和理解。将它分成优化的和非优化的部分可能会更简单,但是很难知道,因为一个极小的例子没有显示真正的代码是什么。下一个C++标准将有STATICIIIF?@?.AuBuIS,没有人知道,但是没有什么被接受或决定。请注意,<代码>如果CONTXPRPR < /代码>(以前称为
    static if
    )现在很可能是C++17的一部分。我想你没有注意到他根本不希望b在优化版本中存在,而不仅仅是初始化-他说的是“更小的内存占用”@gbjbaanb,我想你没有注意到,
    b
    存在于OP的优化版本中,而不是在未优化的版本中,并且在我的版本中也是一样的,不是吗?但是……如何向每个对象添加虚拟指针(至少使每个类实例的大小增加一倍)实现更小的内存占用目标?如果你想取消运行时技巧,那么它将成为一个更好的答案。@MatthieuM。答案的前半部分解决了OP的确切问题,后半部分显示了一个可能有用的替代方案-当你不知道实际co的大小时,你不知道它会使类的大小加倍de(我假设OP的真实代码没有将int设置为零,这可能有点复杂!)我在回答的后半部分的观点是如果“优化”目标是,复制代码可能会导致比使用虚拟函数更差的性能,并且可能会比添加vtable更大地增加可执行文件的大小。就我个人而言,我不认为这种预处理器条件很容易解释,而是将算法分成正交的部分,捕获独立的变化(正如Alexandrescu的现代C++设计)肯定不是TIVI
    struct FooImpl
    {
      virtual void bar() { }
    };
    
    class FooOptimized : FooImpl
    {
      int b;
      void bar()
      {
        b = 0;
      }
    };
    
    struct Algo
    {
      class Foo
      {
        std::unique_ptr<FooImpl> impl;
      public:
        explicit
        Foo(bool optimize)
        : impl(optimize ? new FooOptimized : new FooImpl)
        { }
    
        int a;
    
        void bar()
        {
          impl->bar();
        }
      };
    };
    
    template<bool optimized, typename T> struct dbg_obj {
      struct type {
        // dummy operations so your code will compile using this type instead of T
        template<typename U> type& operator=(const U&) { return *this; }
        operator T&() { return *static_cast<T*>(0); /* this should never be executed! */ }
      };
    };
    template<typename T> struct dbg_obj<false, T> {
      typedef T type;
    };
    
    template<bool enable_optimization>
    class Algo{
      struct Foo{
        int a;
        typename dbg_obj<enable_optimization, int>::type b;
    
        void bar(){
          if(enable_optimization){
            b = 0;
          }
        }
      };
    };
    
    template <typename T> struct FooDependent;
    
    template <>
    struct FooDependent<true> {
        int b;
        void set(int x) { b = x; }
    };
    
    template <>
    struct FooDependent<false> {
        void set(int) {}
    };
    
    struct Foo: FooDependent<enable_optimization> {
        int a;
    
        void bar() { this->set(0); }
    };