【问题标题】:C++: Optimize using templates variablesC++:使用模板变量进行优化
【发布时间】:2009-09-05 21:42:47
【问题描述】:

目前,我有一些代码如下

template<typename Type>
Type* getValue(std::string name, bool tryUseGetter = true)
{
    if(tryUseGetter)
    {
        if(_properties[name]->hasGetter)
        {
            return (Type*)_properties[name]->getter();
        }
        return (Type*)_properties[name]->data;
    }
    else
    {
        return (Type*)_properties[name]->data;
    }
}

有没有办法让 tryUseGetter 成为编译时开关?即将它移动到模板声明,所以它类似于这个

template<typename Type, bool tryUseGetter = true>
...

谢谢。

【问题讨论】:

    标签: c++ optimization templates gcc


    【解决方案1】:

    作为 Dirk 答案的替代方案,您可以将该函数放在 struct 中。模板类可以部分特化(与模板函数相反),因此您可以编写:

    template<typename Type, bool tryUseGetter = true>
    struct getValue;
    
    template<typename Type>
    struct getValue<Type, true>
    {
        Type* run(std::string name)
        {
            if(_properties[name]->hasGetter)
            {
                return (Type*)_properties[name]->getter();
            }
            return (Type*)_properties[name]->data;
        }
    };
    
    template<typename Type>
    struct getValue<Type, false>
    {
        Type* run(std::string name)
        {
            return (Type*)_properties[name]->data;
        }
    };
    

    将其称为getValue&lt;T&gt;::run("foo")getValue&lt;T, false&gt;::run("foo")

    我不能 100% 确定是否允许使用 bool 类型的模板参数,所以也许您应该将其更改为 int

    【讨论】:

    • 任何 POD 类型都可以作为模板参数。例如字符串不是。
    • 仅仅因为 POD 表示“普通旧数据类型”并不意味着 POD 可以在任何地方使用。 POD 结构不允许作为模板参数。
    • bool 是一个整数类型,所以允许是一个“非类型”模板参数。非类型模板参数可以是整型、枚举、指针(指向对象、函数或成员)或引用(指向对象或函数)
    【解决方案2】:

    您可以通过将您的方法分成两个并让编译器分派到适当的方法来获得“try-use-getter”内容的编译时分派:

    struct __try_use_getter { }
    
    external const __try_use_getter tryusegetter;
    
    template<typename Type> 
    Type* 
    getValue(std::string name, const __try_use_getter&)
    {
        if(_properties[name]->hasGetter)
        {
            return (Type*)_properties[name]->getter();
        }
        return (Type*)_properties[name]->data;
    }
    
    template<typename Type> 
    Type* 
    getValue(std::string name)
    {
        return (Type*)_properties[name]->data;
    }
    

    有了这个场景,您将拥有完整的编译时调度:

    int result = getValue("foo", tryusegetter);
    

    会先尝试 getter,而

    int result = getValue("foo");
    

    会立即调用 getter-less 版本。

    【讨论】:

      【解决方案3】:

      以防万一你真的需要它(虽然从性能的角度来看,我怀疑它会引起注意),我会超载

      template<typename Type>
      Type* getValue(std::string const &name)
      {
          if(_properties[name]->hasGetter)
          {
              return (Type*)_properties[name]->getter();
          }
          return (Type*)_properties[name]->data;
      }
      
      template<typename Type, bool tryUseGetter>
      Type *getValue(std::string const &name) 
      {
          if(tryUseGetter)
          {
              return getValue<Type>(name);
          }
          else
          {
              return (Type*)_properties[name]->data;
          }
      }
      

      此外,您应该首先遵循 real 规则:例如,通过 name by-const-reference 而不是传递副本。

      【讨论】:

      • 我用 boost:bind 包装了这个,我似乎无法获得工作参考。
      • 那么我建议你先问另一个问题来解决这个问题,然后再把时间浪费在这些东西上
      • @jameszhao00,我认为我的回答将使您能够使用 boost::bind。
      【解决方案4】:

      您可以使用类型转换运算符和结构getValue,如下所示(用法语法与函数相同):

      template<typename Type, bool tryUseGetter = true> 
      struct getValue {};
      
      template<typename Type>
      struct getValue<Type, true> {
          getValue(const std::string& name) : name(name) {};
          operator Type*() const {
              if(_properties[name]->hasGetter) {
                  return (Type*)_properties[name]->getter();
              }
              return (Type*)_properties[name]->data;
          }
      private:
          const std::string& name;
      };
      
      template<typename Type>
      struct getValue<Type, false> {
          getValue(const std::string& name) : name(name) {};
          operator Type*() const {
              return (Type*)_properties[name]->data;
          }
      private:
          const std::string& name;
      };
      

      用法:

      int main () {
          int* i = getValue<int>( "TEST" ); // true by default
          Xstruct* x = getValue<Xstruct, false>( "XS" ); // false
      }
      

      【讨论】:

        【解决方案5】:

        在将代码变得复杂之前...您是否检查过优化编译器是否已经为您执行此操作?

        【讨论】:

        • 是的,我也是这么想的。我故意复制了部分代码,所以分支完全分开。
        • 顺便说一下,我在我的应用程序上运行了 valgrind/cachegrind,结果发现比较没有优化掉。
        猜你喜欢
        • 2016-01-06
        • 2018-02-22
        • 2016-01-31
        • 2016-07-13
        • 2015-05-09
        • 2015-07-13
        • 1970-01-01
        • 1970-01-01
        • 2020-01-01
        相关资源
        最近更新 更多