如何在constexpr函数中确定数组是否以NULL结尾?

时间:2015-08-01 13:59:55

标签: c++ string c++11 constexpr null-terminated

以下代码用于创建最多8个字符长的字符串的简单散列:

#include <type_traits>
#include <cstdint>
#include <iostream>

template<std::size_t N, std::size_t n=N>
constexpr typename std::enable_if<N<=9 && n==0,
uint64_t>::type string_hash(const char (&)[N])
{
    return 0;
}

template<std::size_t N, std::size_t n=N>
constexpr typename std::enable_if<N<=9 && n!=0,
uint64_t>::type string_hash(const char (&array)[N])
{
    return string_hash<N,n-1>(array) | ((array[n-1]&0xffull)<<(8*(n-1)));
}

对于普通的字符串文字和constexpr以NULL结尾的字符串,它确实可以正常工作。但如果我做这样的事情:

constexpr char s2[] = {1,2,3,4,5,6,7,8,9};
std::cout << string_hash(s2) << "\n";

,输出与字符串"\x1\x2\x3\x4\x5\x6\x7\x8"的输出相同。我尝试在static_assert(array[N-1]==0,"Failed");的定义中添加string_hash,但编译器说array[N-1]不是常量表达式。然后我尝试声明参数constexpr,但编译器说参数不能被声明为constexpr

我该如何检查呢?

2 个答案:

答案 0 :(得分:2)

请注意,尽管constexpr函数可以在编译时使用,但它们并非如此。您不能在运行时参数上添加任何静态断言,因为在编译时不知道参数时,无法评估静态断言。

你可以做的就是你可以对非constexpr函数做同样的事情:抛出一些东西。这并不会阻止使用无效输入调用您的函数,但会阻止无声的错误结果。当您的函数在需要常量表达式的上下文中使用时,编译器将正确地检测它并不返回常量值。

constexpr函数的主体需要是C ++ 11中的单个return语句,但你仍然可以将它放在那里:

return array[N-1] ? throw "bad!" : <your current return expression here>;

选择更好的东西然后扔掉。

答案 1 :(得分:0)

编译器抱怨的原因是因为array在实例化string_hash<N,n>函数时是未知的。实例化时会计算static_cast,而不是在调用时(即使它是constexpr函数)。

请注意,每对<N,n>值都会创建一个函数。如果您使用两个长度相同的constexpr字符串,则将使用完全相同的string_hash实例,但根据参数array[N-1]可能会得到不同的结果。

如果需要,我会继续搜索您问题的准确答案。但是,作为“快速修复”,我是否可以建议更改散列函数,使其始终包含计算中的最后一个字符,是否为0?

更新: 在做了一些挖掘之后,我了解到某种constexpr_assert是您可能想要的,并且目前标准中缺少这种{{1}}。希望他们将来会添加它。您可以查看: