c++ 11递归类模板到复杂错误

标签 c++ templates c++11 recursion

为什么在将 #if 0 更改为 #if 1 时出现“错误 C1202:递归类型或函数依赖上下文太复杂”错误?错误版本更简单,我宁愿使用类似的东西。

我正在尝试编写一个散列函数,以消除编译时间常数长度的循环。真正的哈希函数要复杂得多,这里只是一个简单的例子。

typedef unsigned __int8 U1;
typedef unsigned __int16 U2;
typedef unsigned __int32 U4;
#define  AS1(a_)        (*(U1*)(a_))
#define  AS2(a_)        (*(U2*)(a_))
#define  AS3(a_)        ((U4(((U1*)(a_))[2])<<16) | AS2(a_))
#define  AS4(a_)        (*(U4*)(a_))

#if 0
template<U4 CB> U4 Hash(const char* sz, int n = 0) {
    if (CB >= 4) return Hash<CB - 4>(sz + 4, n ^ AS4(sz));
    if (CB == 3) return n ^ AS3(sz);
    if (CB == 2) return n ^ AS2(sz);
    if (CB == 1) return n ^ AS1(sz);
}
#else
template<U4 CB> U4 Hash(const char* sz) {
    return Hash<CB - 4>(sz + 4, Hash<4>(sz));
}
template<U4 CB> U4 Hash(const char* sz, int n) {
    return Hash<CB - 4>(sz + 4, Hash<4>(sz, n));
}
template<> U4 Hash<1>(const char* sz, int n)        { return n ^ AS1(sz); }
template<> U4 Hash<2>(const char* sz, int n)        { return n ^ AS2(sz); }
template<> U4 Hash<3>(const char* sz, int n)        { return n ^ AS3(sz); }
template<> U4 Hash<4>(const char* sz, int n)        { return n ^ AS4(sz); }
template<> U4 Hash<1>(const char* sz)           { return AS1(sz); }
template<> U4 Hash<2>(const char* sz)           { return AS2(sz); }
template<> U4 Hash<3>(const char* sz)           { return AS3(sz); }
template<> U4 Hash<4>(const char* sz)           { return AS4(sz); }
#endif

int main(int argc, char* argv[])
{
    char* sz = "123456789";
    int n = Hash<9>(sz);
    n += Hash<3>(sz);
    return n;
}

最佳答案

问题是这个函数在编译时是无限递归的:

template<U4 CB> U4 Hash(const char* sz, int n = 0) {
    if (CB >= 4) return Hash<CB - 4>(sz + 4, n ^ AS4(sz));
    if (CB == 3) return n ^ AS3(sz);
    if (CB == 2) return n ^ AS2(sz);
    if (CB == 1) return n ^ AS1(sz);
}

当然,你有 if语句,所以如果你调用 Hash<3>你真的不希望它想要实例化 Hash<-1> ...但是在模板中,必须实例化整个函数体。 Twig 只会在以后被修剪。所以不管CB的值如何, Hash 的任何实例化将继续实例化越来越多的 CB 值(例如 Hash<9> 需要 Hash<5> 需要 Hash<1> 需要 Hash<-3> 需要 Hash<-7> ...)直到它达到编译器模板递归限制或编译器刚好用完内存

另一方面,如果您明确特化所有情况:

template<U4 CB> U4 Hash(const char* sz, int n = 0) {
    return Hash<CB - 4>(sz + 4, n ^ AS4(sz));
}

template <> U4 Hash<3>(const char* sz, int n = 0) {
    return n ^ AS3(sz);
}

// etc.

然后是 Hash<9> 的实例化将导致 Hash<5> 的实例化, 然后 Hash<1>只是一个明确的特化,过程就此停止。

这就是为什么在涉及模板元编程时,您应该将特化视为您的分支和基本递归案例。不要考虑实际的运行时早午餐。

关于c++ 11递归类模板到复杂错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27935471/

相关文章:

c++ - 具有位表示的 bool vector 的自定义实现 - 如何实现 operator[]

用于 STL 容器的 C++ IDE

compression - 如何使用 zlib.h 库将 .zip 文件解压到文件夹中?

c++ - 如何使对模板函数的调用不那么冗长

c++11 - C++ 14 主函数的形式

c++ - 工厂函数的最佳智能指针返回类型是什么?

c++ - Xcode:严格的 C 编译?

c++ - 基于类模板的包装函数

c++ - 在 G++ 中使用 -frepo 选项

c++ - 高效积累