我对元编程的语言特性有点陌生,我正在尝试制作一个简单的 class
与 public static const variables
将通过编译时间常量设置其值:
我想要实现的目标:我想计算一些指数的幂值,这些指数以字节数转换为基数为 2
的位数来衡量。 .所有计算均以 2 为基数。
示例:
1 byte(s) = 8 bits: value = pow(2, 8) = 256; 2 byte(s) = 16 bits: value = pow(2, 16) = 65536 4 byte(s) = 32 bits: value = pow(2, 32) = 4294967296 8 byte(s) = 64 bits: value = pow(2, 64) = 18446744073709551616
我尝试编写一个函数来进行计算,以在尝试使用 constexpr
时计算所需的值。或 const
, 我试过使用 templates
.我想使用 const function
, constexpr function
或 function template
因此:
// constexpr function
constexpr std::uint64_t pow2( const std::uint32_t expInBytes, const std::uint32_t base = 2 ) {
const std::uint32_t expInBits = expInBytes * CHAR_BIT;
return static_cast<std::uint64_t>( expInBits == 0 ? 1 : base * pow2( base, expInBits - 1 ) );
}
// or function template
template<std::uint32_t expInbytes>
constexpr std::uint64_t pow2() {
const std::uint32_t base = 2;
const std::uint32_t expInBits = expInBytes * CHAR_BIT;
return (expInBits == 0 ? 1 : base * pow2<expInBytes-1>() );
}
template<>
constexpr std::uint64_t pow2<0>() {
return 0;
};
// template parameter T not used but needed to use the class as such:
// BitCombinations<>::static_member;
template<typename T = const std::uint32_t>
class BitCombinations {
public: // template // non template
static const std::uint64_t ONE_BYTE = pow2<1>(); // pow2( 1 );
static const std::uint64_t TWO_BYTES = pow2<2>(); // pow2( 2 );
static const std::uint64_t FOUR_BYTES = pow2<4>(); // pow2( 4 );
static const std::uint64_t EIGHT_BYTES = pow2<8>(); // pow2( 8 );
};
通过我的努力,我生成了各种编译时、运行时错误等。最新的尝试我能够得到pow2<>()
的模板版本上面编译和运行,但是我没有得到正确的结果。
我不确定我是否执行了 pow2
是错误的,或者我的语法错误,或者我没有使用 const
或 constexpr
正确,在某些情况下我一直得到 integral constant overflow
作为 MS Visual Studio 2017 CE 编译器的编译时错误。
我一直在为 pow2()
遵循这些模式功能:
- nullptr.me:C++11 constexpr : computing exp at compile time
- prosepoetrycode.potterpcs.net : A simple constexpr power function (C++)
- cppreference.com : math::exp2
- reformatcode.com : c++ power of integer, template meta programming
我似乎无法全神贯注于此,也不知道还能尝试什么。
最佳答案
请注意,您的最后一个案例目前无法实现。 8字节的类型不能存2^64,最大是2^64 - 1,至少在主流架构上,不知道你用的是哪个。
我发现您的函数模板有两个问题。
您仅将结果与
base
相乘一次,但通过执行expInBytes - 1
将位数减 8。所以,你需要将它乘以八次:return (expInBits == 0 ? 1 : base * base * base * base * base * base * base * base * pow2<expInBytes-1>() );
0
的特化返回 0,任何乘以 0 的数字都是 0。:) 如果您认为您用expInBits == 0
,再想一想:expInBits
为0
的唯一方法是expInBytes
为 0,但它不能在主模板中,因为你当expInBytes
为 0 时有专门化!这意味着该分支永远不会被采用,它实际上没有任何效果。
您的函数与 1) 中描述的问题相同,此外,您在递归时向它传递了错误的值(expInBits
而不是 expInBytes
)和顺序是错误的(基数排在最后)。
在我看来,循环更容易理解并且不易出错:
constexpr std::uint64_t pow2(const std::uint32_t expInBytes, const std::uint32_t base = 2) {
const std::uint32_t expInBits = expInBytes * CHAR_BIT;
std::uint64_t result = 1;
for (std::uint32_t i = 0; i < expInBits; ++i)
result *= base;
return result;
}
关于c++计算编译时间常数,同时防止整数常数溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48089550/