Ale*_*x F 3 c++ templates boost boost-preprocessor
假设我需要为0 ... 255值创建一个包含预先计算的位计数值(数字中的1位数)的LUT:
int CB_LUT[256] = {0, 1, 1, 2, ... 7, 8};
Run Code Online (Sandbox Code Playgroud)
如果我不想使用硬编码值,我可以使用漂亮的模板解决方案如何计算32位整数中的设置位数?
template <int BITS>
int CountBits(int val)
{
return (val & 0x1) + CountBits<BITS-1>(val >> 1);
}
template<>
int CountBits<1>(int val)
{
return val & 0x1;
}
int CB_LUT[256] = {CountBits<8>(0), CountBits<8>(1) ... CountBits<8>(255)};
Run Code Online (Sandbox Code Playgroud)
该数组在编译时完全计算.有没有办法避免长列表,并使用某种模板甚至宏生成这样的数组(抱歉!),如:
Generate(CB_LUT, 0, 255); // array declaration
...
cout << CB_LUT[255]; // should print 8
Run Code Online (Sandbox Code Playgroud)
笔记.这个问题不是关于计算一个数字中的1位,而是仅用作示例.我想在代码中完全生成这样的数组,而不使用外部代码生成器.必须在编译时生成数组.
编辑.为了克服编译器限制,我找到了以下解决方案,基于Bartek Banachewicz代码:
#define MACRO(z,n,text) CountBits<8>(n)
int CB_LUT[] = {
BOOST_PP_ENUM(128, MACRO, _)
};
#undef MACRO
#define MACRO(z,n,text) CountBits<8>(n+128)
int CB_LUT2[] = {
BOOST_PP_ENUM(128, MACRO, _)
};
#undef MACRO
for(int i = 0; i < 256; ++i) // use only CB_LUT
{
cout << CB_LUT[i] << endl;
}
Run Code Online (Sandbox Code Playgroud)
我知道这可能是UB ......
使用宏(最近由我为我的代码重新发现)Boost.Preprocessor会很容易 - 我不确定它是否属于"不使用外部代码生成器".
PP_ENUM 版感谢@TemplateRex BOOST_PP_ENUM,正如我所说,我对PP的经验不足:)
#include <boost/preprocessor/repetition/enum.hpp>
// with ENUM we don't need a comma at the end
#define MACRO(z,n,text) CountBits<8>(n)
int CB_LUT[256] = {
BOOST_PP_ENUM(256, MACRO, _)
};
#undef MACRO
Run Code Online (Sandbox Code Playgroud)
主要区别PP_ENUM在于它会在每个元素后自动添加逗号并删除最后一个元素.
PP_REPEAT 版#include <boost/preprocessor/repetition/repeat.hpp>
#define MACRO(z,n,data) CountBits<8>(n),
int CB_LUT[256] = {
BOOST_PP_REPEAT(256, MACRO, _)
};
#undef MACRO
Run Code Online (Sandbox Code Playgroud)
它实际上非常简单易用,但由您来决定是否接受宏.我个人在使用Boost.MPL和模板技术方面苦苦挣扎,发现PP解决方案易于阅读,简短而强大,特别是对于那些类似的枚举.PP相对于TMP的另一个重要优势是编译时间.
至于最后的逗号,所有合理的编译器应该支持它,但是如果你没有,只需将重复次数改为255并手动添加最后一个案例.
您可能还希望重命名MACRO为有意义的内容以避免可能的重新定义.