Reputation: 10425
I have the following code, which is supposed to calculate the number of bits in a byte at compile time.
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();
}
By passing in 1
to the unsigned char
parameter, I'm expecting to get a final result of 8 as it will shift left 8 times until the char becomes 0.
However, compiling with Clang 3.7.1, I get a compilation error:
error: non-type template argument evaluates to 256, which cannot be narrowed to type 'unsigned char' [-Wc++11-narrowing]
Why does this happen? How can I fix it?
Upvotes: 4
Views: 386
Reputation: 10336
One way to avoid this error is to go in reverse: instead of overflowing your char, you start with the maximum and right-shift until you hit zero. You will need a specialisation to make the code work (you will have needed it in either case anyway):
#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();
}
Upvotes: 4
Reputation: 857
There is already a standard macro for that:
#include <climits>
int main() {
std:cout << CHAR_BIT << std::endl;
}
Upvotes: 2
Reputation: 1869
OP said this works, so I'm posting it as answer:
char_bit<(unsigned char)(c << 1), I + 1>::get()
Upvotes: 1
Reputation: 1830
I am not sure why it happens. But I think, you can fix it using template function specialization.
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; }
};
Upvotes: 0