我正在使用 Godbolt 来查看带有 gcc 和 clang 的生成代码。
我试图实现djb2 hash。
gcc 总是试图最好地评估 constexpr 函数。
只有当变量是 constexpr 时,clang 才会评估 constexpr。
让我们看看这个例子:
constexpr int djb2(char const *str)
{
int hash = 5381;
int c = 0;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
int main()
{
int i = djb2("hello you :)");
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,gcc 正在评估一个编译时间 i。但是在运行时叮当响。
如果我将 constexpr 添加到i,clang 也在编译时进行评估。
您知道标准是否对此有所说明吗?
编辑:谢谢大家。所以,据我所知,没有 constexpr …
我使用 MSVC v141 和/std:c++17.
constexpr const char* test(const char* foo) {
return foo + 1;
}
constexpr const char* bc = test("abc");
Run Code Online (Sandbox Code Playgroud)
编译得很好,而
constexpr const char* test(const char* foo) {
constexpr auto bar = foo;
return bar + 1;
}
constexpr const char* bc = test("abc");
Run Code Online (Sandbox Code Playgroud)
失败:
错误 C2131:表达式未计算为常量
失败是由在其生命周期之外读取变量引起的
注意:参见'foo'的用法
这是正确的行为还是 MSVC 中的错误?
编译器是否保证评估环境constexpr中"tautologies"(例如始终true或false分别)的布尔表达式constexpr?
例如,在以下代码片段(在标有 的行(1))中,我在constexpr环境中调用了一个函数,我打算在non-constexpr传递函数时导致编译时错误。至少我使用的编译器 ( g++-10.0) 是这样做的,即使它也可以意识到表达式总是true不计算它。我问这个问题的原因是 - 据我所知 - 在非 constepxr 上下文中,像这样的表达式i >= std::numeric_limits<int>::min()被优化true为int i.
#include <limits>
constexpr int example_function() { return 1;}
constexpr bool compileTimeErrorDesired = example_function() || true; // (1)
Run Code Online (Sandbox Code Playgroud)
如果(1) 保证in 的行为,则可以在 aconcept中使用它,以执行不同的代码,具体取决于是否可以在编译时评估作为模板参数提供的函数。我实现了一个非常短的 ( 7 lines-of-code) 示例,它在编译器资源管理器中完全做到了这一点。
如果使用非 constexpr 函数调用,行 (1) …
我写了这个简单的辅助constexpr函数:
#include <cstdint>
constexpr bool isEven(uint32_t value) { return ((value%2) == 0); }
Run Code Online (Sandbox Code Playgroud)
这非常简单。我想知道这是否被认为是确定某个整数值是奇数还是偶数的最有效方法?目前我并不担心为不同的积分类型模板化这个函数。我只是在追求效率和性能,同时牢记便携性。
编辑
为了提供一些上下文,我可能会在一个循环中调用这个函数,该循环可以迭代 100,000 次到 100,000,000 次或更多...所以效率是这里的关键,但可移植性仍然是一个因素...
正如其他人在评论或答案中所述,我曾通过检查最低有效位来考虑“按位运算”,但是,我不确定编译器是否会在这种情况下优化模运算符。
关于可移植性,我不确定“字节序”或“整体约定”是否是应该使用实现的主要因素。考虑一个仅实现 1 的补码而不是 2 的补码的系统,或者使用 Big Endian 而不是 Little 的系统,可能需要加以考虑。
为什么这段代码在编译时出错?我对“ ”的了解(以及这个)if constexpr表明该else块不应该被编译。
if constexpr (true) {
int a = 10;
} else {
int b = 10
}
Run Code Online (Sandbox Code Playgroud)
错误是:
error: expected ‘,’ or ‘;’ before ‘}’ token
Run Code Online (Sandbox Code Playgroud)
使用的编译器:g++ version 7.5.0
编译时我使用了-std=c++17标志。
PS缺少的';' 是故意的,只是为了检查是否else正在编译。
为什么非编译时计算函数“产品”可以是constexpr?
#include <iostream>
constexpr int product(int x, int y) {
return x * y;
}
int main(int argc, char* argv[]) {
using namespace std;
int x1, y1 = 0;
cout << "input x1:\n";
cin >> x1;
cout << "input y1:\n";
cin >> y1;
const int a = product(x1, y1);
cout << a << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud) 我有一个关于编译时函数的问题。我知道 static_assert 应该只适用于可以在编译时评估/计算的类型。所以它不适用于 std::string (然而,gcc10 中不支持 constexpr std::string)但可以使用 std::array(当我在编译时知道大小时)。我正在观看 Jason Turner 的 C++ Weekly,所以这个片段来自这一集https://www.youtube.com/watch?v=INn3xa4pMfg。
代码在这里:https : //godbolt.org/z/e3WPTP
#include <array>
#include <algorithm>
template<typename Key, typename Value, std::size_t Size>
struct Map final
{
std::array<std::pair<Key, Value>, Size> _data;
[[nodiscard]] constexpr Value getMappedKey(const Key& aKey) const
{
const auto mapIterator = std::ranges::find_if(_data, [&aKey](const auto& pair){ return pair.first == aKey;});
if(mapIterator != _data.end())
{
return mapIterator->second;
}
else
{
throw std::out_of_range("Key is not in the map");
}
}
};
enum class OurEnum …Run Code Online (Sandbox Code Playgroud) template<typename T>
T f() {
if constexpr (std::is_same<T, int>::value) {
T t = 10;
}else {
T t;
}
return t;
}
Run Code Online (Sandbox Code Playgroud)
我对上述代码的理解f是
int t = 10;
return t;
Run Code Online (Sandbox Code Playgroud)
或者
T t = // some default value for T
return t;
Run Code Online (Sandbox Code Playgroud)
取决于T. 在两者中都会有一个名为 的标识符t。为什么编译器仍然抱怨use of undeclared identifier 't'?。
编译器在解析constexpr语句之前是否检查未声明的标识符?
有什么区别constexpr和consteval?
consteval int x1 = 2;
constexpr int x2 = 5;
Run Code Online (Sandbox Code Playgroud)
使用 constexpr 比使用 consteval 更好吗?
为什么用auto关键字定义变量不带有constexpr用于初始化它的表达式的“性质”?
例如,请考虑以下代码:
#include <string_view>
constexpr std::string_view f() { return "hello"; }
static constexpr std::string_view g() {
constexpr auto x = f(); // (*)
return x.substr(1, 3);
}
int foo() { return g().length(); }
Run Code Online (Sandbox Code Playgroud)
使用 GCC 10.2 和--std=c++20 -fsanitize=undefined -O3,编译为:
foo():
mov eax, 3
ret
Run Code Online (Sandbox Code Playgroud)
但是,如果我们删除 (*) 行上的 constexpr,我们将得到一个 27 行的程序,其中包含一堆指针、一个长字符串常量等。
笔记:
autowrt constexprness的一般行为。该示例只是表明 GCC 不会将 x 视为constexpr我们没有明确告诉它。c++ ×10
constexpr ×10
c++20 ×4
c++17 ×3
auto ×1
c++-concepts ×1
c++11 ×1
clang ×1
consteval ×1
constinit ×1
gcc ×1
if-constexpr ×1
if-statement ×1
performance ×1