如何确保在constexpr函数中接受一个数组,该数组以null结束
How to make sure in a constexpr function taking an array that the array is 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";
,输出将与字符串"x1x2x3x4x5x6x7x8"
相同。我试过在string_hash
的定义中添加static_assert(array[N-1]==0,"Failed");
,但编译器说array[N-1]
不是常量表达式。然后我尝试声明参数constexpr
,但是编译器说不能声明参数constexpr
。
我该如何检查呢?
请记住,虽然constexpr
函数可以在编译时使用,但它们并不需要。您不能在运行时参数上添加任何静态断言,因为当编译时不知道参数时,静态断言将无法求值。
你能做的和你对非constexpr
函数做的是一样的:抛出一些东西。这并不能防止用无效输入调用函数,但可以防止无声的错误结果。当你的函数在需要常量表达式的上下文中使用时,编译器会正确地检测到它没有返回常量值。
在c++ 11中,constexpr
函数体需要是一个单独的返回语句,但您仍然可以在那里容纳它:
return array[N-1] ? throw "bad!" : <your current return expression here>;
一定要挑个好点的来扔。
编译器抱怨的原因是因为string_hash<N,n>
函数实例化时array
是未知的。static_cast
在实例化时求值,而不是在调用时求值(即使它是constexpr函数)。
请注意,将为每一对<N,n>
值创建一个函数。如果你使用两个相同长度的constexpr字符串,将使用完全相同的string_hash
实例,但根据参数array[N-1]
可能会给出不同的结果。
更新:在做了一些挖掘之后,我了解到某种constexpr_assert
可能是您在案例中需要的,并且目前在标准中缺少它。希望他们将来会添加它。您可能需要检查:
- g++没有't编译包含assert的constexpr函数
- constexpr函数的可选断言
- http://ericniebler.com/2014/09/27/assert-and-constexpr-in-cxx11
- 取消引用结束指针到数组类型的一个
- 数组对象的生存期是否在重用其元素存储时结束?
- 二进制数组中最大连续 1 的起始和结束索引,以 C++ 为单位
- 当字符串为"\0"时如何结束 2D 字符数组?
- 如何获取由 new 创建的数组的开始和结束
- 重写自定义数组类的运算符/开始/结束
- C++ char 数组特征:为什么字符串在数组结束之前停止?
- C 排序无法解析标识符开始和结束吗?(将数组保持在一起)
- C 读取输入,直到线char数组的结束
- 将数组作为函数参数传递,并在其上调用开始/结束方法
- 当我使用 += 将数字添加到数组中时,无论数字是什么,它总是以 0 结束
- C 指针数组使用STL开始和结束
- STD ::结束如何在本机数组上工作
- 如果用户输入 -1 作为动态数组中的数字,如何结束程序
- 通过在上一个数组结束后立即存储下一个元素来扩展数组
- char数组在结束前包含空字符
- 如何将排序的元素从数组中的起始索引获取到结束索引
- std::以原始字符数组结束
- 如果最后一个地址是0xFFFFFFFF,我如何获取数组结束后的地址
- While(数组结束)-如何识别