【问题标题】:Illegal use of explicit template arguments while combating recursion errors在处理递归错误时非法使用显式模板参数
【发布时间】:2020-12-25 06:08:46
【问题描述】:

我正在尝试实现 SHA256 哈希函数,以便在程序中使用一些编译时功能。预处理的一个步骤是在给定公式的情况下填充消息/输入数据。填充量自然必须是正整数。该算法依赖于块处理,每个块只能容纳这么多的数据,所以如果数据大于一个块,我们需要更多的块。我使用递归解决了这个问题,但这会引发 C1202 - 模板定义是递归的或超出了复杂性限制。

template <uint32_t DataLength, uint32_t ChunkSize, uint32_t Chunks>
int GetBitsToAppend() {
    static int BitsToAppend = ChunkSize*Chunks - DataLength - 1 - (ChunkSize / 8);
    return 0 > BitsToAppend ? GetBitsToAppend<DataLength, ChunkSize, Chunks+1>() : BitsToAppend;
}

我尝试通过添加显式模板定义来解决它,但这反而引发了一个新错误; C2768,非法使用显式模板参数。代码如下:

template<uint32_t DataLength, uint32_t ChunkSize>
int GetBitsToAppend<DataLength, ChunkSize, 1024>() {
    int BitsToAppend = ChunkSize*Chunks - DataLength - 1 (ChunkSize / 8)
}

如果我使用正常的循环函数,它会按预期工作,但是由于在编译时需要知道处理数组的长度,这会中断。例如:

int GetBitsToAppend(uint32_t DataLength, uint32_t ChunkSize, uint32_t Chunks) {
    static int BitsToAppend = ChunkSize * Chunks - DataLength - 1 - (ChunkSize>>3);
    return 0 > BitsToAppend ? GetBitsToAppend(DataLength, ChunkSize, Chunks+1) : BitsToAppend;
}

template <typename T, size_t OutputSize, size_t ByteSizeInput, size_t Rounds, size_t ChunkSize>
std::bitset<OutputSize> SHA(const T data) {

    // Pre-processing
    const uint32_t DataLength = ByteSizeInput << 3;
    const uint32_t BitsToAppend = GetBitsToAppend(DataLength, ChunkSize, 1); // Run-time calculation

    const uint32_t TargetSize = (DataLength + BitsToAppend + (ChunkSize>>3) + 1) / sizeof(uint32_t);
    std::array<uint32_t, TargetSize> ProcessArray; // Invalid template argument.
    
    // Copy data into ProcessArray and perform remaining preprocessing
//........

ChunkSize 是常量,由函数的模板参数给出,ByteSizeInput 也是如此。 ChunkSize>>3是指在预处理中附加的整数的大小,在SHA256/224中为64位,在SHA384/512中为128位。阿卡。相应的块大小除以八。

有谁知道如何解决这个问题?

【问题讨论】:

    标签: c++ templates recursion


    【解决方案1】:

    在 C++17 及更高版本中,可以使用 if constexpr 修复此问题,如下所示:

    template <uint32_t DataLength, uint32_t ChunkSize, uint32_t Chunks>
    int GetBitsToAppend() {
        constexpr int BitsToAppend = ChunkSize*Chunks - DataLength - 1 - (ChunkSize / 8);
        if constexpr (0 > BitsToAppend)
            return GetBitsToAppend<DataLength, ChunkSize, Chunks+1>();
        else
            return BitsToAppend;
    }
    

    Live demo

    【讨论】:

    • 谢谢!这解决了递归问题。您是否也碰巧知道为什么这不会评估为 constepxr?它当然似乎没有任何歧义,但我不是专家。 GetBitsToAppend 中的所有计算都是常量还是在编译时确定?对不起,如果这是一个愚蠢的问题。
    • 我想出了一个解决方案,请参阅下面的答案。
    【解决方案2】:

    除了先生好心提供的答案。桑德斯:

    编译器不理解(根据我的经验)工作模板在简单地分配给变量时评估为 constexpr,从而导致一些进一步的错误。将 constepxr 添加到 GetBitsToAppend 以及 BitsToAppend 的函数签名和 sum 变量 TargetSize 可提供所需的结果:

    template <uint32_t DataLength, uint32_t ChunkSize, uint32_t Chunks>
    constexpr int GetBitsToAppend() {
        constexpr int BitsToAppend = ChunkSize * Chunks - DataLength - 1 - (ChunkSize/8);
        #pragma warning(suppress:4984) //Remove compatibility warning
        if constexpr (0 > BitsToAppend)
             return GetBitsToAppend<DataLength, ChunkSize, (Chunks+1)>();
        else
            return BitsToAppend;
    }
    
    template <typename T, size_t OutputSize, size_t ByteSizeInput, size_t Rounds, size_t ChunkSize>
    std::bitset<OutputSize> SHA(const T data) {
        //Pre-processing
        constexpr uint32_t DataLength = ByteSizeInput << 3;
        constexpr uint32_t BitsToAppend = GetBitsToAppend<DataLength, ChunkSize, 1>();
        
        constexpr uint32_t TargetSize = (DataLength + BitsToAppend + (ChunkSize>>3)+1) / sizeof(uint32_t)
        std::array<uint32_t, TargetSize> ProcessArray; // Compiles!
    //...
    

    【讨论】:

    • 此代码中使用的标头:&lt;stdint.h&gt; 用于 uint32_t、size_t 等,&lt;array&gt; 用于 std::array 和 &lt;bitset&gt; 用于 std::bitset
    猜你喜欢
    • 2021-07-27
    • 2018-07-30
    • 1970-01-01
    • 2010-11-27
    • 1970-01-01
    • 2017-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多