【问题标题】:Exclude part of function template during compile time在编译时排除部分函数模板
【发布时间】:2016-11-12 09:27:33
【问题描述】:

请考虑以下代码。它是一个函数模板,根据其位宽对T 类型进行操作。实际代码更复杂,但这无关紧要:

template <typename T> T MyFunc(T t)
{
   constexpr const uint8_t typeBitCount = sizeof(T)*8;

   // more code here that works fine for all widths

   if (typeBitCount >= 32)
   {
      if (...)
      {
         return t >> 16; // warning right shift count >= width of type
      }

      if (typeBitCount >= 64)
      {
         if (...)
         {
            return t >> 32; // warning right shift count >= width of type
         }
      }
   }
}

我也将它与 8 位类型一起使用。在这种情况下,我会收到警告(请参阅注释行)。不幸的是,即使使用constexpr,C++ 也无法在编译期间评估if 条件。我可能会压制警告,但这对我来说似乎很老套。我宁愿在编译时排除有问题的代码。

如何解决这个问题(可能不会破坏代码并且不会产生冗余)?

我使用的是 GCC 5.4.0。

【问题讨论】:

  • 所有代码都必须编译。取决于typeBitCount 的选择只发生在运行时,而不是编译时。因此,当编译器遇到这些行时,您会收到警告。
  • 这很清楚。问题是如何尽可能干净地解决这个问题。
  • 如果你有一个 C++14 编译器,你也许可以将整个函数变成一个 constexpr 函数并让它评估一个编译时间(取决于“这里的更多代码...... “ 部分)。这可能会解决你的一些问题。或者您可以将函数专门用于 8 位类型,并将常见的“这里有更多代码...”部分放在单独的函数中。
  • 在 C++14 之前,您需要引入一个模板化的帮助类,其中一个模板参数是一个整数值,等于sizeof(T)(或sizeof(T)*8),并且(可能是静态的) ) 成员函数来执行所需的操作。然后使用模板部分特化为sizeof(T) 的每个有效值实例化该类及其函数。这意味着您不能“不将代码分解成碎片”就可以逃脱,但这是寻求编译时机制的代价 - 模板(部分)专业化是基本的编译时机制,在运行时完成使用if
  • @Some程序员老兄:使用C++14我实际上可以制作函数constexpr。但是警告仍然存在。

标签: c++ c++11 templates bit-shift compile-time


【解决方案1】:

我会计算有问题的转变,以便:

  • 当要执行移位时,它具有所需的值 32,
  • 如果不应该执行,它有一些小的值0:

    ....
    constexpr uint8_t shift2 = (typeBitCount >= 64) ? 32 : 0;
    ....
    if (typeBitCount >= 64)
      {
         if (...)
         {
            return t >> shift2;
         }
      }
    ....
    

【讨论】:

    【解决方案2】:

    您可以使用类似于this answer 的部分模板特化来使用仿函数实现依赖于类型大小的函数:

    // Base implementation for unsupported size and type.
    template <typename T, size_t TSize>
    class MyFuncImpl;
    
    // 32-bit specialization.
    template <typename T>
    struct MyFuncImpl<T, 4>
    {
        T operator()(const T t) const
        {
            return t >> 16;
        }
    };
    
    // 64-bit specialization.
    template <typename T>
    struct MyFuncImpl<T, 8>
    {
        T operator()(const T t) const
        {
            return t >> 32;
        }
    };
    
    // Calling this functor will calculate the correct bit-shift at compile time and not emit warnings.
    template <typename T>
    T MyFunc(const T t)
    {
        return MyFuncImpl<T, sizeof(T)>()(t);
    }
    

    您还可以为 8 位和 16 位类型添加额外的特化。你可以这样使用它:

    int main()
    {
        uint32_t test1 = 1235434;
        std::cout << MyFunc(test1) << std::endl;
    
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      我终于在没有任何模板的情况下解决了这个问题。我改用普通重载。我将代码分成几部分,每种类型都有一个函数,将这些函数从 64 位宽度级联到 8 位宽度。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-11-26
        • 2018-04-20
        • 2015-02-18
        • 1970-01-01
        • 1970-01-01
        • 2016-01-30
        • 1970-01-01
        • 2011-08-05
        相关资源
        最近更新 更多