c++:使用 constexpr 对数据进行 XOR 不起作用

c++: using constexpr to XOR data doesn't work

这是我的代码:

template<int... I>
class MetaString1
{
public:
    constexpr MetaString1(constexpr char* str)
        : buffer_{ encrypt(str[I])... } { }

const char* decrypt()
{
    for (int i = 0; i < sizeof...(I); ++i)
        buffer_[i] = decrypt1(buffer_[i]);
    buffer_[sizeof...(I)] = 0;
    return buffer_;
}

private:
    constexpr char encrypt(constexpr char c) const { return c ^ 0x55; }
    constexpr char decrypt1(constexpr char c) const { return encrypt(c); }

private:
    char buffer_[sizeof...(I)+1];

};


#define OBFUSCATED1(str) (MetaString1<0, 1, 2, 3, 4, 5>(str).decrypt())



int main()
{

    constexpr char *var = OBFUSCATED1("Post Malone");

    std::cout << var << std::endl;
    return 1;
}

这是我正在阅读的论文中的代码 Here。思路很简单,对XOR的参数OBFUSCATED1进行解密,然后解密回原来的值。

我遇到的问题是 VS 2017 给我错误提示 function call must have a constant value in constant expression

如果我只离开 OBFUSCATED1("Post Malone");,我没有错误,程序是 运行,但我注意到如果我在 constexpr MetaString1 构造函数中有断点,断点就会命中,这意味着 constexpr 不会在编译时求值。据我了解,这是因为我没有 "force" 编译器在编译期间通过将结果分配给 constexpr 变量来评估它。

所以我有两个问题:

  1. 为什么我有错误 function call must have a constant value in constant expression?

  2. 为什么人们在使用constexpr函数时使用templateclasses?据我所知,template classes 在编译期间得到评估,因此使用 template class 和 constexpr 只是一种推动编译器在编译期间评估这些功能的方法?

  1. 您尝试将非 constexpr 类型分配给 constexpr 类型变量, 什么是不可能的
constexpr char *var = OBFUSCATED1("Post Malone")
//              ^^^   ^^^^^^^^^^^
// type of var is constexpr, return type of OBFUSCATED1 is const char*

  1. constexpr 关键字是在 C++11 中引入的,因此在使用此关键字之前,您必须编写复杂的 TMP 内容以使编译器在编译时执行操作。由于 TMP 是图灵完备的,理论上你不需要比 TMP 多的东西,但由于 TMP 编译速度慢且难以准备,你可以使用 constexpr 来表达你想要在编译时评估的东西可读的方式。虽然 TMP 和 constexpr 之间没有关联,这意味着,您可以在没有模板 类.
  2. 的情况下自由使用 constexpr

要实现您想要的效果,您可以保存两个版本的字符串:

template <class T>
constexpr T encrypt(T l, T r)
{
    return l ^ r;
}
template <std::size_t S, class U>
struct in;
template <std::size_t S, std::size_t... I>
struct in<S, std::index_sequence<I...>>
{
    constexpr in(const char str[S])
        : str_{str[I]...}
        , enc_{encrypt(str[I], char{0x12})...}
    {}
    constexpr const char* dec() const
    {
        return str_;
    }
    constexpr const char* enc() const
    {
        return enc_;
    }

protected:
    char str_[S];
    char enc_[S];
};
template <std::size_t S>
class MetaString1
    : public in<S, std::make_index_sequence<S - 1>>
{
public:
    using base1_t = in<S, std::make_index_sequence<S - 1>>;
    using base1_t::base1_t;
    constexpr MetaString1(const char str[S])
        : base1_t{str}
    {}
};

并像这样使用它:

int main()
{
    constexpr char str[] = "asdffasegeasf";
    constexpr MetaString1<sizeof(str)> enc{str};
    std::cout << enc.dec() << std::endl;
    std::cout << enc.enc() << std::endl;
}