c ++(XORString):"递归类型或函数依赖关系上下文过于复杂"

时间:2017-09-21 17:28:39

标签: c++ c++11 templates variadic-templates template-meta-programming

我试图在编译时使用以下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个字符传递给它时会弹出错误。

任何其他想法都会受到赞赏......或者如果有人有另一个编译时字符串混淆实现,可以采用任意长度的字符串文字......这将是伟大的!

2 个答案:

答案 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;
 }