伪造静态If在C ++中

时间:2012-07-21 13:24:57

标签: c++ optimization if-statement static static-if

我正在测试各种优化的组合,对于这些我需要静态 - 如http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Static-If-I-Had-a-Hammer中所述,以启用和禁用特定优化。 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;
      }
    }
  };
};

(是的,在我的情况下,从数据布局中删除b的较小内存占用量是相关的。)

目前我使用非常糟糕的黑客伪造它。我正在寻找一种更好的方法。

档案a.h

#ifndef A_H
#define A_H
template<class enable_optimization>
class Algo;
#include "b.h"
#endif

文件b.h(此文件是从Python脚本自动生成的)

#define ENABLE_OPTIMIZATION 0
#include "c.h"
#undef
#define ENABLE_OPTIMIZATION 1
#include "c.h"
#undef

文件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
    }
  };
};

有谁知道更好的方法吗?从理论上讲,它可以使用模板元编程完成,起初我使用它。至少我使用它的方式是屁股的痛苦,并导致完全不可读和臃肿的代码。使用上面的hack可以显着提高生产力。

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

3 个答案:

答案 0 :(得分:6)

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

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();
      }
    };
  };

不需要进行元编程,只需根据优化是否已启用为新类型并将其专门化而将各个部分分开。

因为新类型在空时被用作基类(即没有FooOptimized::b成员),所以它不会占用空间,因此sizeof(Algo<false>::Foo) == sizeof(int)


(随意忽略这个答案的其余部分,它没有直接解决问题,而是提出了一种不同的方法,它有不同的权衡。是否“更好”或更不完全取决于细节真实的代码,在问题中给出的简单示例中没有显示。)

作为一个相关但又独立的问题,AlgoAlgo::Foo部分取决于是否启用优化仍取决于模板参数,因此,虽然您只编写一次这些代码,但编译器将生成两组目标代码。根据代码中的工作量以及它的使用方式,您可能会发现将其更改为非模板代码是有利的,即用动态多态替换静态多态。例如,您可以将enable_optimization标志设置为运行时构造函数参数而不是模板参数:

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();
    }
  };
};

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

答案 1 :(得分:1)

注意:就目前而言,这种方法不起作用,因为如果没有为该成员分配空间,似乎无法在类中拥有成员。如果您知道如何使其工作,请随时编辑。

你可以使用这样的成语:

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;
      }
    }
  };
};

如果禁用优化,则会为您提供正常的int成员。如果启用了优化,则b的类型是没有成员的结构,不会占用任何空间。

由于您的方法bar使用看起来像运行时if的内容来决定是否访问b,而不是像模板专门化那样清晰的编译时机制,所有您在b上使用的操作也必须可以从虚拟结构中获得。即使相关部分永远不会被执行,并且编译器很可能将它们优化掉,但首先是正确性检查。因此,行b = 0也必须为替换类型进行编译。这就是虚拟分配和虚拟投射操作的原因。虽然两者都足以满足您的代码要求,但我还是将它们包括在内,以防它们在某些其他方面证明是有用的,并且如果您需要它们,还可以了解如何添加更多代码。

答案 2 :(得分:0)

Jonathan Wakely提出的静态解决方案(不是动态解决方案)是要走的路。

这个想法很简单:

  1. 将“特定”数据隔离到自己的类中(相应地模板化和专门化)
  2. 对该数据的所有访问都完全移交给专门的类(接口必须是统一的)
  3. 然后,为了不产生空间开销,您可以通过继承此特殊类的特化来使用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) {}
    };
    

    然后我们可以使用EBO将其注入Foo

    struct Foo: FooDependent<enable_optimization> {
        int a;
    
        void bar() { this->set(0); }
    };
    

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