【问题标题】:Non-type template argument narrowing in template recursion模板递归中的非类型模板参数缩小
【发布时间】:2016-07-07 09:31:22
【问题描述】:

我有以下代码,它应该在编译时计算一个字节中的位数。

template<unsigned char c, size_t I>
struct char_bit
{
    static constexpr size_t get() noexcept {
        return c > 0 ? char_bit<c << 1, I + 1>::get() : I
    }
};

int main()
{   
    std::cout << char_bit<1, 0>::get();
}

通过将1 传递给unsigned char 参数,我期望得到最终结果 8,因为它将向左移动 8 次,直到字符变为 0。

但是,使用 Clang 3.7.1 进行编译时,出现编译错误:

错误:非类型模板参数计算结果为 256,不能 缩小到类型 'unsigned char' [-Wc++11-narrowing]

为什么会这样?我该如何解决?

【问题讨论】:

  • 你试过了吗:char_bit::get() 或 char_bit ::get() ?
  • @SvenNilsson 为什么这两个都有效?
  • @SvenNilsson 我不会做第一个,因为它会将一个字节的大小限制为 8 位。今天这听起来是合法的,但嘿,你永远不知道。除此之外,这与 OP 的目标精神背道而驰。
  • 是的,它们可以工作,因为我猜它们将值限制为最大 255

标签: c++ templates c++11


【解决方案1】:

避免此错误的一种方法是反向操作:不要溢出字符,而是从最大值开始并右移直到达到零。您将需要专业化才能使代码正常工作(无论如何您都需要它):

#include <iostream>
using namespace std;

template<unsigned char c, size_t I>
struct char_bit
{
    static constexpr size_t get() noexcept {
        return char_bit< (c >> 1), I + 1>::get();
    }
};

template<size_t I>
struct char_bit<0, I>
{
    static constexpr size_t get() noexcept {
        return I;
    }
};


int main()
{   
    constexpr unsigned char c = static_cast<unsigned char>(-1);
    std::cout << char_bit<c, 0>::get();
}

【讨论】:

    【解决方案2】:

    已经有一个标准宏:

    #include <climits>
    
    int main() {
        std:cout << CHAR_BIT << std::endl;
    }
    

    【讨论】:

      【解决方案3】:

      OP 说这行得通,所以我将其发布为答案:

      char_bit<(unsigned char)(c << 1), I + 1>::get()
      

      【讨论】:

        【解决方案4】:

        我不知道为什么会这样。但我认为,您可以使用模板函数专业化来修复它。

        template<unsigned char c, size_t I>
        struct char_bit
        {
            static constexpr size_t get() noexcept {
                return char_bit<(c << 1), I + 1>::get();
            }
        };
        
        template <size_t I>
        struct char_bit<0, I>
        {
            static constexpr size_t get() noexcept { return I; }
        };
        

        【讨论】:

          猜你喜欢
          • 2017-03-18
          • 2021-07-27
          • 2021-03-18
          • 1970-01-01
          • 1970-01-01
          • 2019-04-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多