我的应用包含众多ID。我想最终让其他人可以查看代码,但是不要让运行时反向工程师轻松查找容易知道的ID。此外,在开发期间,在日志文件中具有常量ID以便于调试是有帮助的。但是在运行时我想通过在Release编译期间生成这些ID来使它们随机。使用<random>
lib的建议代码可以在下面的GetRandomId1()
中看到。 constexpr
可以像在switch语句中一样使用代码。但是,我在提议的函数中使用constexpr
时遇到问题,因为<random>
不兼容constexpr
。还有另一种在编译时生成随机数的方法吗?或者是在编译时生成随机数,以便在运行时用作constexpr
概念的常量?
#include <iostream>
#include <random>
// this is the code I would like to use to generate a random number at compile time
/*constexpr */int GetRandomId1()
{
std::random_device rd; // non-deterministic seed
std::mt19937 gen( rd() ); // with constexpr uncommented:
// error C3250: 'rd': declaration is not allowed in 'constexpr' function body
// error C3249: illegal statement or sub-expression for 'constexpr' function
// error C3250: 'gen': declaration is not allowed in 'constexpr' function body
std::uniform_int_distribution<> distri( 1000, 9999 ); // with constexpr uncommented:
// error C3250: 'distri': declaration is not allowed in 'constexpr' function bod
// error C3249: illegal statement or sub-expression for 'constexpr' function
// error C2134: 'std::uniform_int<_Ty>::operator ()': call does not result in a constant expression
return distri( gen );
}
// this code is what works so far
constexpr int GetRandomId2()
{
return 22; // how to make somewhat random?
}
constexpr int AAA = 10;
//constexpr int AAA = GetRandonId1(); // error: is not constexpr function
constexpr int BBB = GetRandomId2(); // ok
void Func1( long ab )
{
switch( ab )
{
case AAA:
std::cout << AAA << std::endl;
break;
case BBB:
std::cout << BBB << std::endl;
break;
}
}
int main()
{
Func1( 22 ); // ok: prints 22
return 0;
}
我正在寻找一个像我提议的那样直接,可维护的解决方案,而不像How can I generate dense unique type IDs at compile time?中提出的那样大量使用模板。同样在这篇帖子中,@ jmihalicza指向Random number generator for C++ template metaprograms研究论文。本文描述了使用模板元编程生成编译时随机数,这是一项复杂的尝试,可以完成IMO constexpr
(我敢说或应该已经?)设计的任务。
由于应用程序架构原因,我不必担心ID冲突,所以这不是一个问题。应用程序代码将确保不会返回重复项。
答案 0 :(得分:5)
前段时间我提供了一个constexpr
随机数生成器here,用于constexpr
字符串加密的相关目的,以帮助您关注与之相关的对手。
我认为它具有与mt19937类似的加密安全性,mt19937是一个非常复杂的线性反馈生成器,并且无论如何都不是真正的加密安全。
此代码中的想法是使用__TIME__
和__LINE__
作为生成器的种子。
typedef uint32_t u32;
typedef uint64_t u64;
typedef unsigned char uchar;
template<u32 S, u32 A = 16807UL, u32 C = 0UL, u32 M = (1UL<<31)-1>
struct LinearGenerator {
static const u32 state = ((u64)S * A + C) % M;
static const u32 value = state;
typedef LinearGenerator<state> next;
struct Split { // Leapfrog
typedef LinearGenerator< state, A*A, 0, M> Gen1;
typedef LinearGenerator<next::state, A*A, 0, M> Gen2;
};
};
// Metafunction to get a particular index from generator
template<u32 S, std::size_t index>
struct Generate {
static const uchar value = Generate<LinearGenerator<S>::state, index - 1>::value;
};
template<u32 S>
struct Generate<S, 0> {
static const uchar value = static_cast<uchar> (LinearGenerator<S>::value);
};
// Seed
#define RNG_SEED ((__TIME__[7] - '0') * 1 + (__TIME__[6] - '0') * 10 + \
(__TIME__[4] - '0') * 60 + (__TIME__[3] - '0') * 600 + \
(__TIME__[1] - '0') * 3600 + (__TIME__[0] - '0') * 36000) + \
(__LINE__ * 100000)
我没有尝试使用constexpr
而不是模板来重写它,但是我认为在C ++ 11标准中使用constexpr
函数来处理所有复杂的事情并不比模板。它只能在C ++ 14标准中变得很好,当你实际上可以拥有局部变量等等时。
无论如何它仍然不应该那么难,这个发电机实现并不是那么糟糕。
你绝对需要放弃在编译时与std::random_device
交谈的梦想。 IIRC,在libc++
实现中,基本上是std::fopen("/dev/urandom")
上的薄包装器。我不知道任何允许constexpr
计算中的文件系统操作的C ++标准或提议。 :)