我试图在编译时使用以下XORString模板/宏来加密字符串文字:
#pragma once
#include <string>
namespace utils {
template <int X> struct EnsureCompileTime {
enum : int {
Value = X
};
};
//Use Compile-Time as seed
#define compile_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 )
constexpr int LinearCongruentGenerator(int Rounds) {
return 1013904223 + 1664525 * ((Rounds > 0) ? LinearCongruentGenerator(Rounds - 1) : compile_seed & 0xFFFFFFFF);
}
#define Random() EnsureCompileTime<LinearCongruentGenerator(10)>::Value //10 Rounds
#define RandomNumber(Min, Max) (Min + (Random() % (Max - Min + 1)))
template <int... Pack> struct IndexList {};
template <typename IndexList, int Right> struct Append;
template <int... Left, int Right> struct Append<IndexList<Left...>, Right> {
typedef IndexList<Left..., Right> Result;
};
template <int N> struct ConstructIndexList {
typedef typename Append<typename ConstructIndexList<N - 1>::Result, N - 1>::Result Result;
};
template <> struct ConstructIndexList<0> {
typedef IndexList<> Result;
};
template <typename Char, typename IndexList> class XorStringT;
template <typename Char, int... Index> class XorStringT<Char, IndexList<Index...> > {
private:
Char Value[sizeof...(Index)+1];
static const Char XORKEY = static_cast<Char>(RandomNumber(0, 0xFFFF));
template <typename Char>
constexpr Char EncryptCharacterT(const Char Character, int Index) {
return Character ^ (XORKEY + Index);
}
public:
__forceinline constexpr XorStringT(const Char* const String)
: Value{ EncryptCharacterT(String[Index], Index)... } {}
const Char *decrypt() {
for (int t = 0; t < sizeof...(Index); t++) {
Value[t] = Value[t] ^ (XORKEY + t);
}
Value[sizeof...(Index)] = static_cast<Char>(0);
return Value;
}
const Char *get() {
return Value;
}
};
#define XORSTR( String ) ( utils::XorStringT<char, utils::ConstructIndexList<sizeof( String ) - 1>::Result>( String ).decrypt() )
}
代码不是我的,我对c ++模板或元编程知之甚少。代码按照小字符串(<250个字符)的方式工作,但是,我需要让它在长字符串上工作(数千个字符)。
当我在带有数千个字符的字符串文字上使用XORSTR
宏时,我得到一个&#34;递归类型或函数依赖关系上下文过于复杂&#34;编译时出错。
我已经尝试弄清楚代码究竟是做什么的,似乎这些行以递归方式从输入字符串构造某种编译时数组(?),ConstructIndexList
行是什么生成错误:
template <typename IndexList, int Right> struct Append;
template <int... Left, int Right> struct Append<IndexList<Left...>, Right> {
typedef IndexList<Left..., Right> Result;
};
template <int N> struct ConstructIndexList {
typedef typename Append<typename ConstructIndexList<N - 1>::Result, N - 1>::Result Result;
};
由于我对模板知之甚少,所以我不确定如何准确地解决这个问题。
我有一个想法是传递原始文字的宏子串然后连接它们(以程序方式,而不是手动),但是......我不知道如何进行编译时子串/连接操作文字,也许这是不可能的。
另一个想法是简单地手动拆分我的文字,将拆分字符串单独传递给XORSTR
,然后手动连接结果,但这会在我的代码中造成很多混乱....考虑到我需要在数万个字符上运行XORSTR
,并且当&gt; ~250个字符传递给它时会弹出错误。
任何其他想法都会受到赞赏......或者如果有人有另一个编译时字符串混淆实现,可以采用任意长度的字符串文字......这将是伟大的!
答案 0 :(得分:1)
编译器有限制,您正在尝试将模板嵌套到字符串长度的深度。几年前你的编译器会为你设置你的计算机,今天你得到一个很好的错误信息,它将来不太可能改进。 (即使编译器实际上找到了通向字符串末尾的方法,你也会对编译的速度感到非常不满。)
你应该考虑离线编码你的文字 - 也就是说,使用一个单独的工具(通过你的makefile或你得到的任何构建系统)在选定的源头上生成生成的头文件(或者cpps,无论如何) - 后者你的#include。也许您可以重新利用现有的可编程模板生成器,或者您可以使用代码中带有“标记”的现有工具来指示要编码的字符串 - awk在这里工作得很好 - 您甚至可以将字符串放在单独的“消息”文件中并从中生成标题。
P.S。其中一些限制记录在特定编译器的文档中。您可以在那里查看模板嵌套的限制,或模板可变参数的数量,这样的东西。据我所知,标准仅建议这些最大限制的最小值,而非常低。
答案 1 :(得分:1)
如果我没错,你的ConstructIndexList
使({rou})std::make_integer_sequence
的工作(可从C ++ 14获得)。
所以我想你可以写
template <typename>
struct cilH;
template <int ... Is>
struct cilH<std::integer_sequence<int, Is...>>
{ using type = IndexList<Is...>; };
template <int N>
struct ConstructIndexList
{ using Result = typename cilH<decltype(std::make_integer_sequence<int, N>{})>::type; };
避免你的递归瓶颈。
(但请记住#include <utility>
)。
但是,我想,如果您为索引使用ConstructIndexList
类型而不是std::size_t
,则可以完全避免使用int
。
我想您的代码可以简化如下
#include <array>
#include <string>
#include <utility>
#include <iostream>
namespace utils
{
constexpr std::size_t compSeed {
(__TIME__[7] - '0') * 1U
+ (__TIME__[6] - '0') * 10U
+ (__TIME__[4] - '0') * 60U
+ (__TIME__[3] - '0') * 600U
+ (__TIME__[1] - '0') * 3600U
+ (__TIME__[0] - '0') * 36000U };
constexpr std::size_t linCongrGen (std::size_t rou)
{ return 1013904223U + 1664525U * ((rou > 0U)
? linCongrGen(rou - 1U)
: compSeed & 0xFFFFFFFFU); }
constexpr std::size_t randNumber (std::size_t mn, std::size_t mx)
{ return mn + (linCongrGen(10U) % (mx - mn + 1U)); }
template <typename, typename>
class XorStringT;
template <typename Char, std::size_t ... Is>
class XorStringT<Char, std::index_sequence<Is...>>
{
private:
Char Value[sizeof...(Is)+1U];
static constexpr Char XORKEY = Char(randNumber(0, 0xFFFF));
public:
constexpr XorStringT (Char const * const String)
: Value{ Char(String[Is] ^ (XORKEY + Is))... }
{ }
constexpr std::array<Char, sizeof...(Is)+1U> decrypt () const
{ return { { Char(Value[Is] ^ (XORKEY + Is)) ..., Char(0) } }; }
Char const * get () const
{ return Value; }
};
}
template <typename T, std::size_t N>
constexpr auto xorStr (T (&s)[N])
{ return utils::XorStringT<T,
decltype(std::make_index_sequence<N - 1U>{})>( s ); }
int main()
{
constexpr auto xst = xorStr("secrettext");
std::cout << xst.get() << std::endl;
std::cout << xst.decrypt().data() << std::endl;
}