如何在 constexpr 函数中实现回退运行时
How can I have a fallback run-time implementation in a constexpr function
上下文
我正在制作一个数学库,我需要使用sqrt()
.
由于sqrt()
不是一个constexpr
函数,我已经实现了constexpr
版本的sqrt()
和一个更快的std::sqrt()
使用汇编,所以必须在运行时使用.
现在,我正在使用所有这些来计算向量的长度, 这个函数可以constexpr
,因为我正在使结构中constexpr
一切可能。
constexpr inline Real length(( const { return const_sqrt(lengthSquared(((;}
这将起作用,如果在非constexpr
上下文中调用lenght()
函数,它只是在运行时运行,但我的运行时实现sqrt()
比const_sqrt()
更快。
问题
如何根据函数是在编译时还是运行时执行来切换为使用一种或另一种实现.
像这样:
constexpr inline Real length(( const { 返回IN_RUN_TIME ?fast_sqrt(lengthSquared((( : const_sqrt (lengthSquared(((; }
在 c++20 中,函数std::is_constant_evaluated
可用于此目的:
constexpr Real length() const {
return ! std::is_constant_evaluated()
? fast_sqrt(lengthSquared())
: const_sqrt(lengthSquared());
}
据我所知,在 c++20 之前,没有办法达到这种效果,这就是它被添加到语言中的原因。
另外,请注意,constexpr
暗示inline
因此关键字在这里是多余的。
唯一符合标准的解决方案是使用std::is_constant_evaluated
,正如 cigien 所建议的那样:
constexpr inline Real length() const
{
return std::is_constant_evaluated()
? fast_sqrt<Real>(lengthSquared())
: const_sqrt<Real>(lengthSquared());
}
这种方法的问题在于,只有当length()
的返回值用于初始化constexpr
变量时,std::is_constant_evaluated()
才会返回true
,或者需要constexpr
。
在编译时已知lengthSquared()
的值(因此可以使用const_sqrt
(但不需要constexpr
length()
的返回值的情况下,这是次优的。然后is_constant_evaluated
将返回false
,因此将使用fast_sqrt
,不必要地将1的计算推迟到运行时。
解决方法是使用非标准的GCC内置(也受Clang支持(:__builtin_constant_p
。与std::is_constant_evaluated
不同,它有一个"表达式"参数,并检查表达式的值在编译时是否已知(这可能取决于优化设置(。
我建议如果可用,应该使用__builtin_constant_p
,否则回退到std::is_constant_evaluated
。(如果您使用的是 C++20 之前的编译器,则此内置是您唯一的选择。
#ifdef __GNUC__ // Defined by GCC and Clang
#define KNOWN_AT_COMPILE_TIME(...) __builtin_constant_p(__VA_ARGS__)
#else
#define KNOWN_AT_COMPILE_TIME(...) std::is_constant_evaluated()
#endif
constexpr inline Real length() const
{
return KNOWN_AT_COMPILE_TIME(lengthSquared())
? fast_sqrt<Real>(lengthSquared())
: const_sqrt<Real>(lengthSquared());
}
1我假设fast_sqrt
在编译时不起作用。否则,没有必要单独const_sqrt
.
- 如何在 constexpr 函数中实现回退运行时
- 在C++中实现回调
- C++通过回退到 C 进行类型双关语
- SFINAE - 如果更复杂的功能失败,则回退到默认功能
- 如何编写模板重载函数,并在模板参数不允许实例化某个类时触发回退
- 在C 中的类中实现回调功能
- 调用成员函数(如果存在),回退到自由函数,反之亦然
- 当函数不存在时,SFINAE 回退
- 在C 抽象类中实现回调(对于C库)为纯虚拟
- 回退到复制构造函数不起作用
- C++ - 在 C++ 中实现回调时的允许错误
- 可视化如何使用C++在 SQLite3 数据库上实现回滚事务
- 如何使用接口实现回调
- FindResourceEx和回退语言
- 最后手段/包罗万象/回退模板过载
- 在Qt中实现回调
- 具有最近路径前缀回退的查找树
- 运算符<<() 失败时回退到 to_string()
- 如果未实现除法运算符,则SFINAE回退
- 在c++中,如何用回退包装默认标头