目前,您不能使用static_assert
来验证constexpr
函数的参数,即使对它的所有调用确实都是constexpr
。这是有意义的,因为编译器仍然必须创建这个函数的非constexpr示例化,以防其他模块试图调用它。可悲的是,即使函数是static
或在匿名名称空间中,情况也是如此。
然而,C++20将引入一个新的关键字consteval
,它类似于constexpr
,但它不允许以非constexpr的方式调用函数。在这种情况下,编译器可以确定函数参数在编译时总是已知的。因此,理论上应该可以用static_assert
验证它们。
问题是:标准允许吗?
示例:
#include <iostream>
consteval char operator""_bchar(const char text[], const size_t length)
{
static_assert(length == 8, "Binary char has to have 8 digits!"); // <-- This is currently not possible.
uint8_t byte = 0;
for (size_t i = 0; i != length; ++i)
{
byte <<= 1;
byte |= text[i] == '1' ? 0b00000001 : 0b00000000;
}
return byte;
}
int main()
{
std::cout << "01000001"_bchar << std::endl;
return 0;
}
我问这个问题是因为我要写一些用户定义的文字(比示例更复杂)。我可以选择使用编译器扩展来处理验证,或者稍等编译器更新,然后编写完全符合标准的代码。
3条答案
按热度按时间xmakbtuz1#
consteval是否允许在函数参数上使用static_assert?
不。函数参数从来没有,也将继续不能作为常量表达式使用。
在被常量求值的东西和可用作常量表达式的东西之间是有区别的。
consteval
确保我们处于常量求值上下文中,但它也不会导致所有内容都成为常量表达式。为了允许函数参数可以用作常量表达式,你需要将所有内容隐式地设置为模板:
现在
foo(20)
和foo(30)
返回不同的类型。那是个模板要了解为什么这是一个基本的和固有的限制,可以在Andrew萨顿的Translation and evaluation: A mental model for compile-time metaprogramming中找到重要的背景阅读:
有一个编译时求值的心理模型,将其与翻译过程物理分离,这对我非常有帮助。特别是,它帮助我理解了什么是不可能的(例如,在评估期间示例化模板)。这有助于为其他大型和复杂的语言功能修剪设计空间。希望其他人也会发现这篇文章很有帮助。
但是,对于
static_assert
,您可以添加一个解决方法,只导致编译失败。这只是添加了在常量求值期间不能使用的任何内容。比如:如:
jchrr9hc2#
我同意上面的评论者-不可能使用
static_assert()
w/函数参数,但是,仍然有可能在参数条件下触发consteval函数的编译错误。也就是说,为了获得与static_assert
相同的效果。技巧是
(length != 8)
触发除以零,这不是常量表达式。编译错误看起来像(gcc-11):
!!!警告警告!!!:仅适用于
consteval
函数**。如果在constexpr
函数中使用,您的程序将被/除以零错误杀死。使用assert()
代替或抛出异常。pu82cl6c3#
我已经修改了@巴里的答案中的技术,以便在所有
consteval
,constexpr
和常规函数中工作。当对C++23的支持更好时,可以使用
if consteval
来改进它: