我正在尝试在编译时计算字符串文字的长度.为此,我使用以下代码:
#include <cstdio>
int constexpr length(const char* str)
{
return *str ? 1 + length(str + 1) : 0;
}
int main()
{
printf("%d %d", length("abcd"), length("abcdefgh"));
}
Run Code Online (Sandbox Code Playgroud)
一切都按预期工作,程序打印4和8.由clang生成的汇编代码显示结果在编译时计算:
0x100000f5e: leaq 0x35(%rip), %rdi ; "%d %d"
0x100000f65: movl $0x4, %esi
0x100000f6a: movl $0x8, %edx
0x100000f6f: xorl %eax, %eax
0x100000f71: callq 0x100000f7a ; symbol stub for: printf
Run Code Online (Sandbox Code Playgroud)
我的问题:标准是否保证length函数将在编译时进行评估?
如果这是真的,编译时字符串文字计算的大门刚刚为我打开...例如,我可以在编译时计算哈希值等等......
是否有可能根据C++ 11中的C++ 11表达式是否为常量表达式(即constexpr)生成编译时布尔值?关于SO的几个问题与此有关,但我在任何地方都没有看到直接答案.
假设我有一个向量长度计算函数,它有一个附加inc参数(这告诉相邻元素之间的距离)。一个简单的实现是:
float calcLength(const float *v, int size, int inc) {
float l = 0;
for (int i=0; i<size*inc; i += inc) {
l += v[i]*v[i];
}
return sqrt(l);
}
Run Code Online (Sandbox Code Playgroud)
现在,calcLength可以使用两种inc参数进行调用:何时inc在编译时已知,何时未知。我想要一个calcLength针对常见编译时值inc(如 1)的优化版本。
所以,我会有这样的东西:
template <int C>
struct Constant {
static constexpr int value() {
return C;
}
};
struct Var {
int v;
constexpr Var(int p_v) : v(p_v) { }
constexpr int value() const {
return v;
}
}; …Run Code Online (Sandbox Code Playgroud) 我正在实现一个constexpr int foo();功能。在 的主体中foo(),我想在编译时做一些不同的事情(并且可能返回一些不同的东西),而在运行时做一些不同的事情。
使用 C++20,我可以使用std::is_constant_evaluated:
constexpr int foo() { return std::is_constant_evaluated() ? 123 : 456 };
Run Code Online (Sandbox Code Playgroud)
但是如果我使用的是 C++17(或更早版本)怎么办 - 我可以用同样的效果做什么?
注意:特定于编译器的解决方案是可以接受的(尽管不太理想)。
我有以下代码在 c++20 中执行我想要的操作:
#include <iostream>
struct IntContainer
{
int value;
constexpr IntContainer(int init):value(init)
{
if(std::is_constant_evaluated())
{
value*=2;
}
else
{
std::cout<<"Constructed at runtime"<<std::endl;
}
}
};
int main()
{
constexpr int fixed=99;
int runtime;
std::cout<<"Enter runtime int value"<<std::endl;
std::cin>>runtime;
constexpr IntContainer fixed_container(fixed);
IntContainer runtime_container(runtime);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
对于fixed整数值,它默默地构造我的容器并将该值加倍,对于整runtime数值,它使用详细构造。该实现允许我声明fixed_container为constexpr.
我必须使用 c++20 才能使用该std::is_constant_evaluated功能,但我仅限于 c++17。是否有一些聪明的模板魔法我可以用来在没有此功能的情况下保持相同的行为?
给定一个 constexpr 函数,是否有办法在编译时调用该函数时创建编译时错误,并在运行时调用该函数时返回哨兵值?
不幸的是,我无法使用异常,因为它们在构建中被禁用。
这主要用于与枚举之间的转换以及与字符串之间的转换。如果开发人员输入了不正确的值,最好让构建失败,而不是希望他们在运行时看到错误,但由于我们可以从未知来源获取值,因此该值有可能无效,我们不这样做不想在运行时崩溃。
演示用例:
#include <fmt/core.h>
#include <iostream>
// from: https://stackoverflow.com/a/63529662/4461980
// if C++20, we will need a <type_traits> include for std::is_constant_evaluated
#if __cplusplus >= 202002L
#include <type_traits>
#endif
constexpr bool is_constant_evaluated() {
#if __cplusplus >= 202002L
return std::is_constant_evaluated();
#elif defined(__GNUC__) // defined for both GCC and clang
return __builtin_is_constant_evaluated();
#else
// If the builtin is not available, return a pessimistic result.
// This way callers will implement everything in a constexpr way.
return true;
#endif
}
enum …Run Code Online (Sandbox Code Playgroud)