C++ 生成整数对数的常量数组的项值
我似乎无法理解这段用c++编写的代码:C++ 生成整数对数的常量数组的项值,c++,algorithm,c-preprocessor,C++,Algorithm,C Preprocessor,我似乎无法理解这段用c++编写的代码: static const char LogTable256[256] = { #define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6), LT(7), LT(7), LT(7), LT(7),
static const char LogTable256[256] =
{
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
};
如何使用循环生成相同的数组 \define
行可以出现在代码中的任何地方,只要它们的用法遵循它们。由于它们是预处理器指令,因此以下各项之间没有区别:
static const char LogTable256[256] =
{
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
};
及
如果第二个对您有意义,那么请放心,就编译器和程序的行为而言,第一个同样好。第一种可能会误导读者认为宏是在变量声明的范围内定义的,这是不正确的
如何使用循环生成相同的数组
不能使用循环来实现这一点,因为char数组是const
该算法所做的是,它用从-1到7的数字填充一个char数组,从1开始,每个数字插入的频率是之前的两倍。这可以通过两个简单的嵌套循环完成,或者一个循环,pow
和memset
。但要使其工作,字符数组不能是常量。预处理器指令的位置在技术上并不重要,除非它在使用它定义的LT
宏之前。更传统的格式将把它放在数组定义之前。它不限于定义的范围:宏不尊重范围
要定义数组而不使用宏,可以使用单例,例如Meyers的单例
一次性初始化是构造函数的工作,我就是这样做的,一个Meyers的单例,带有类类型对象,其构造函数计算数组项值:
auto logarithms()
-> std::array<signed char, 256> const&
{
struct Wrapper
{
std::array<signed char, 256> items_;
static void append( int const n, int const value, signed char*& p )
{
for( int i = 1; i <= n; ++i ) { *p++ = value; }
}
Wrapper()
{
items_[0] = -1;
signed char* p = &items_[1];
for( int i = 0; i < 8; ++i ) { append( 1 << i, i, p ); }
assert( p == &*items_.end() );
}
};
static Wrapper const the_array;
return the_array.items_;
}
自动对数()
->std::数组常量&
{
结构包装器
{
std::数组项;
静态void append(int const n、int const value、有符号字符*&p)
{
对于(int i=1;i您甚至可以使用constexpr
,当constexpr
对象初始化时可以调用它。填充数组是可能的,但是std::array
缺少一些constexpr
声明,这些声明将在C++17
中引入将其rt到一个std::array
,带有一个辅助函数到\u array
,该函数也将添加到标准/tr2中
#include <array>
#include <algorithm>
#include <cassert>
// this is from cppreference
namespace detail {
template <class T, std::size_t N, std::size_t... I>
constexpr std::array<std::remove_cv_t<T>, N>
to_array_impl(T (&a)[N], std::index_sequence<I...>)
{
return { {a[I]...} };
}
}
template <class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N])
{
return detail::to_array_impl(a, std::make_index_sequence<N>{});
}
constexpr auto make()
{
int a[256] = {-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,};
for(size_t i=4, n=16, start=16; i <= 7; ++i, n *= 2)
{
for(size_t j=0; j != n; ++j)
{
a[start + j] = i;
}
start += n;
}
return to_array(a);
}
int main() {
static const int LogTable256[256] =
{
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
};
auto constexpr a = make();
assert( std::equal( std::begin(a), std::end(a), std::begin(LogTable256) ) );
return 0;
}
将这么多代码复制到一个空文件中,并运行(如果可用)此命令“g++-E file.cpp>file\u preprocessed.cpp
”,您可能会看到LT(n)
macro会在每个实例中将其替换为16个n-s。似乎有人正在使用这种基于ascii的值存储char
。对于循环,没有系统的方法来生成此序列,因此最好保持如上所述。LT(n)每个将被值n替换8次。因此,对于i>4,您可以简单地使用for循环;最好您自己尝试并向我们展示您的progress@RamandeepPunia实际上是16次。结果是-1,然后是一个255个值的列表,从0到7,你总能找到n的2^n个实例。@TinyT,是的,你是对的。这是16次。不知怎的,我“第一个也一样好”,不,不是。它将宏定义隐藏在其他文本中,表示程序员错误地认为宏仅限于它定义的范围。源代码是关于与人通信的。@RSahu这有助于我理解数组是如何创建的,但我还需要用python重现相同的代码,我不知道就我所知,python没有任何类似于C预处理器的东西。然而,python是一种动态语言。你很有可能完成你想做的事情。请随意提问另一个问题,并提供所有细节。-1“使用循环无法做到这一点,因为char数组是const
”是错误的(在公平的解释意义上)或是正确的,但没有意义(在完全字面意义上)。最后的断言“但要想做到这一点,char数组不能是const”是错误的™.这里有两个主要问题:(1)代码不使用Visual C++ 2015编译,因为它是非常C++ 14的特定代码,(2)复制,我不确定它是否一定会被优化掉。作为成本,这种方法购买了在编译时表达式中使用对数的能力。我不认为我会做这种交易。;-)@阿尔夫。我没有检查VC++,只是GCC 6.1。我认为可以通过创建一个<代码> CONTXPRP<代码>类来避免复制。它初始化了构造函数中的表。这也可以用VC++编译。我在更新2上看到了y,我想我已经看到了更新5。(更新3中引入了邪恶的呼叫总部潜力的主要原因是,为生成的可执行文件配备了这一功能,所以我停止了更新。我希望微软不要被黑暗面所操纵!)Alf这是我问题的一个很好的答案。但是如果我只是动态分配数组而不是使用内置的std::array,不是更好吗?@MuhammadAliQadri:对于静态大小常量数组,几乎不管大小,动态分配(即使用std::vector
)这只是一个无用的开销。这就是std::array
的用途。此数组的空间在程序加载的映像中。您可以使用内置的原始数组,而不是std::array
,但是返回类型规范变得有点复杂,->符号字符常量(&)[256]
。使用C++03函数声明语法甚至更不可编程。
#include <array>
#include <algorithm>
#include <cassert>
// this is from cppreference
namespace detail {
template <class T, std::size_t N, std::size_t... I>
constexpr std::array<std::remove_cv_t<T>, N>
to_array_impl(T (&a)[N], std::index_sequence<I...>)
{
return { {a[I]...} };
}
}
template <class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N])
{
return detail::to_array_impl(a, std::make_index_sequence<N>{});
}
constexpr auto make()
{
int a[256] = {-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,};
for(size_t i=4, n=16, start=16; i <= 7; ++i, n *= 2)
{
for(size_t j=0; j != n; ++j)
{
a[start + j] = i;
}
start += n;
}
return to_array(a);
}
int main() {
static const int LogTable256[256] =
{
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
};
auto constexpr a = make();
assert( std::equal( std::begin(a), std::end(a), std::begin(LogTable256) ) );
return 0;
}
class LogTable
{
public:
constexpr LogTable()
{
for(size_t i=4, n=16, start=16; i <= 7; ++i, n *= 2)
{
for(size_t j=0; j != n; ++j)
{
a[start + j] = i;
}
start += n;
}
}
constexpr int operator[](size_t i) const
{
return a[i];
}
private:
int a[256] = {-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,};
};
int main() {
static const int LogTable256[256] =
{
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
};
LogTable constexpr l;
for(auto i=0; i != 256; ++i)
{
assert(LogTable256[i] == l[i]);
}
return 0;
}