【问题标题】:Does this mimic perfectly a function template specialization?这是否完美地模仿了功能模板专业化?
【发布时间】:2010-04-11 11:22:31
【问题描述】:

由于以下代码中的函数模板是类模板的成员,因此如果不专门化封闭类就无法专门化它。

但如果编译器的全部优化已开启(假设 Visual Studio 2010),以下代码中的 if-else-statement 是否会得到优化?如果是这样,这是否意味着对于所有实际目的,这是一个没有任何性能成本的函数模板专业化?

template<typename T>
struct Holder
{
    T   data;

    template<int Number>
    void saveReciprocalOf();
};

template<typename T>
template<int Number>
void Holder<T>::saveReciprocalOf()
{
    //Will this if-else-statement get completely optimized out
    if(Number == 0)     data = (T)0;
    else                data = (T)1 / Number;
}

//-----------------------------------
void main()
{
    Holder<float> holder;
    holder.saveReciprocalOf<2>();
    cout << holder.data << endl;
}

【问题讨论】:

    标签: c++ templates visual-studio-2010 function specialization


    【解决方案1】:

    它可能会被优化。但是,如果您想确定,您可以通过使用模板来使用编译时if,例如Boost 的 MPL if_ 实现。

    或者您可以使用 SFINAE (Boost.enable_if)。

    【讨论】:

      【解决方案2】:

      通常解决这类问题的方法是通过重载

      template<typename T>
      struct Outer {
        template<int I>
        void inner() { 
          inner(int_<I>());
        }
      
      private:
        template<int I>
        struct int_ { };
      
        void inner(int_<0>) {
          // for I == 0
        }
      
        template<int I>
        void inner(int_<I>) {
          // for others...
        }
      };
      

      这很好地模拟了显式特化,甚至在其他路径的类型检查会变得疯狂的情况下也有效(与if 解决方案不同)

      // ...
        template<int I>
        void inner(int_<I>) {
          int tmp[I];
        }
      // ...
      

      之所以有效,是因为只有在I != 0 时才会采用此路径。现在在你的情况下,我首先想知道为什么你不只是传递一个普通的函数参数。您似乎并不需要I 的编译时间特性。

      // works just fine too in your example
      template<typename T>
      void Holder<T>::saveReciprocalOf(int Number)
      {
          // Will this if-else-statement get completely optimized out
          if(Number == 0)     data = (T)0;
          else                data = (T)1 / Number;
      }
      

      如果编译器内联函数调用,这也很有可能被优化。在没有严格必要的情况下使用模板非类型参数只会限制该函数不使用运行时值的能力。

      【讨论】:

      • 我认为当检查变量是编译时间常数时,编译器更有可能优化掉不必要的条件块。但是,如果使用常规函数参数时也有可能发生优化,那么我想这没有任何意义。
      • @Zeroes00 如果您真的认为它会影响性能,我建议先编译然后查看程序集。下面是一个令人印象深刻的编译器优化示例:stackoverflow.com/questions/2419650/…
      【解决方案3】:

      谢谢。因为我想确定条件被优化了(因为它需要经常在循环内部深处调用,并且我在循环外部使用 switch-case 来选择正确的路径),我可能最终会使用enable_if_c something就像下面的代码:

      using boost::enable_if_c;
      
      template<typename T>
      struct Dummy
      {    
          template<int N>
          typename enable_if_c<N==2,bool>::type             isPrimary() {return true;}
      
          template<int N>
          typename enable_if_c<N==3,bool>::type             isPrimary() {return true;}
      
          template<int N>
          typename enable_if_c<N==5,bool>::type             isPrimary() {return true;}
      
          template<int N>
          typename enable_if_c<N!=2&&N!=3&&N!=5,bool>::type isPrimary() {return false;}
      };
      

      对我来说,这似乎比 Johannes 的建议更简洁。尽管最后一个(默认)情况可能会变得非常丑陋。

      【讨论】:

      • 我想完全有可能计算一个值是否是模板元编程的素数(至少到某些值 - 无论如何你的最多只能工作 6 个),因此没有运行时函数完全打电话。
      • 我实际上不需要主数或倒数,我只是将它们用作示例,以了解如何在类模板中专门化函数模板。
      • 请注意int_ 也可以通过boost 获得。这是boost::mpl::int_
      猜你喜欢
      • 1970-01-01
      • 2020-06-26
      • 1970-01-01
      • 1970-01-01
      • 2011-04-12
      • 1970-01-01
      • 2019-08-19
      • 2020-07-18
      • 1970-01-01
      相关资源
      最近更新 更多