我们正在尝试加速 Clang 和 Visual C++ 下的一些代码(GCC 和 ICC 也可以)。我们认为可以用来constexpr告诉 Clang 一个值是编译时常量,但它会导致编译错误:
$ clang++ -g2 -O3 -std=c++11 test.cxx -o test.exe
test.cxx:11:46: error: function parameter cannot be constexpr
unsigned int RightRotate(unsigned int value, constexpr unsigned int rotate)
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
这是简化的情况:
$ cat test.cxx
#include <iostream>
unsigned int RightRotate(unsigned int value, constexpr unsigned int rotate);
int main(int argc, char* argv[])
{
std::cout << "Rotated: " << RightRotate(argc, 2) << std::endl;
return 0;
}
unsigned int RightRotate(unsigned int …Run Code Online (Sandbox Code Playgroud) 在下面的代码中,我创建了一个长度为 6 的数组,并在前 3 个元素中使用 1、2 和 3 对其进行初始化。然后我将前 3 个元素复制到后 3 个元素。然后我按顺序打印所有元素。
\n\nstd::array<int, 6> bar = {1, 2, 3};\n\nint main(){\n // Copy the first 3 elements to the last 3 elements\n std::copy(bar.begin(), bar.end() - 3, bar.end() - 3);\n\n // Print all the elements of bar\n for(auto& i: bar) std::cout << i << std::endl;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n它工作正常,但是当我尝试创建数组时,constexpr它不再编译:
constexpr std::array<int, 6> bar = {1, 2, 3};\n\nint main(){\n // Copy the first 3 elements to the last 3 elements\n …Run Code Online (Sandbox Code Playgroud) 我尝试在 g++ 和 clang++ 中使用相同的 constexpr,最新版本和参数“-std=c++11”。Clang 编译没有问题,但 G++ 返回错误。来源是:
#include <functional>
enum class LoggerLevel : unsigned {
NO_LEVEL = 0,
VERBOSE = 1 << 0,
DEBUG = 1 << 1,
INFO = 1 << 2,
WARNING = 1 << 3,
ERROR = 1 << 4,
FATAL = 1 << 5,
ALL_LEVELS = 0 | VERBOSE | DEBUG | INFO | WARNING | ERROR | FATAL,
};
constexpr LoggerLevel operator|(LoggerLevel lhs, LoggerLevel rhs) noexcept {
return static_cast<LoggerLevel>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs));
}
constexpr …Run Code Online (Sandbox Code Playgroud) 使用 C++17/C++20 x64 gcc/clang 构建时,以下代码段会产生编译错误,而通过直接取消引用迭代器*std::max_element(std::begin(arr), std::end(arr))工作正常。关于为什么的任何想法?我还观察到了自 C++20 以来已成为 constexpr 的其他标准算法的类似行为,例如std::upper_bound
int main()
{
constexpr std::array<int,5> arr = {1,2,3,4,5};
constexpr auto it = std::max_element(std::begin(arr), std::end(arr));
}
Run Code Online (Sandbox Code Playgroud)
source>:11:73: error: '(((std::array<int, 5>::const_pointer)(& arr.std::array<int, 5>::_M_elems)) + 16)' is not a constant expression
11 | constexpr auto it = std::max_element(std::begin(arr), std::end(arr));
|
Run Code Online (Sandbox Code Playgroud) 我正在尝试创建一个可变int参数向量并对+它们执行运算符。
例如:
vec<1,2,3> v1;
vec<4,5> v2;
auto res = v1+v2;
res.print(); // should print 5 7 3 vec<5,7,3> is the result.
Run Code Online (Sandbox Code Playgroud)
现在我想创建 struct vecSum,它将总结给它的向量;
namespace ex {
template<int... N>
struct vec
{
static const int size = sizeof...(N);
void print() {
((std::cout << N << " "), ...);
}
};
template<int...N, int...M, int ...S>
auto add(vec<N...>, vec<M...>, std::index_sequence<S...>) {
constexpr int arr1[sizeof...(S)]{ N... };
constexpr int arr2[sizeof...(S)]{ M... };
return vec<(arr1[S] + arr2[S])...>{};
}
template<int...N, …Run Code Online (Sandbox Code Playgroud) 在以下 C++20 函数模板中:
template<int i>
void f() {
if constexpr (i == 1)
g();
else if constexpr (i == 2)
h();
else
??? // <--error
}
Run Code Online (Sandbox Code Playgroud)
有什么我们可以写的东西,???这样f<3>()在编译时调用就会失败?
我想知道以下是否应该或不应该在 C++17 中编译
enum class E
{
A, B
};
constexpr E x = static_cast<E>(2);
Run Code Online (Sandbox Code Playgroud)
这在 Ubuntu 20.04 上使用 GCC 9.3.0 和 Clang 10.0.0 编译。
我的问题是
我认为不应该。有很多关于未定义行为 (UB) 和枚举的帖子,但我找不到任何在常量表达式上下文中提出的帖子。此外,大多数帖子使用底层类型,我认为范围枚举没有任何固定的底层类型。因为我没有获得ISO标准的副本,我将把最新的C ++发现有17草案cppreference.com这里在下面的推理。
首先,我们找到将带有 UB 的表达式从常量表达式中丢弃的段落
[expr.const]/2:表达式 e 是核心常量表达式,除非 e 的计算遵循抽象机的规则,将计算以下表达式之一:
带小节
[expr.const]/2.6 : 具有未定义行为的操作,如本国际标准的 [intro] 至 [cpp] 条款 [?注:包括,例如,有符号整数溢出(条款 [expr]),某些指针算术([expr.add]),除以零,或某些移位操作?—?尾注?];
这告诉我们常量表达式可能不包含 UB。
然后,我们找到关于从 int 到 enum 的静态转换的部分
[expr.static.cast]/10 : 整数或枚举类型的值可以显式转换为完整的枚举类型。如果原始值在枚举值 ( [dcl.enum] )的范围内,则该值不变。否则,行为是未定义的。浮点类型的值也可以显式转换为枚举类型。结果值与将原始值转换为枚举的基础类型 ([conv.fpint]) 以及随后的枚举类型相同。
这告诉我们,如果操作数在目标枚举的范围内,则静态转换的结果是明确定义的。该部分参考[decl.enum]/8关于枚举值的范围(太长无法在此处发布,我也无法正确设置格式)。无论如何,它表示非固定基础类型枚举的有效值范围由可以适合最小和最大枚举(以两个补码格式)之间的所有值的最小位集定义。
最后,在示例代码中应用这三个部分,我们可以说可以同时包含 A = 0 和 B = 1 的最小位域的大小为 …
情况如下:Foo带有模板参数的类int N有一个静态成员变量float val。的值val对应于N并且永远不会改变,所以我希望它是constexpr。
我知道初始化静态 constexpr 成员变量的常用方法是:
// ok, but not what I want
template <int N>
struct Foo {
static constexpr float val { 0.0f };
};
template <int N>
constexpr float Foo<N>::val;
Run Code Online (Sandbox Code Playgroud)
但是因为val是在类范围内初始化的,所以我不能val为不同的N.
如果val不是constexpr但是const,这有效:
// ok, but not what I want
template <int N>
struct Foo {
static const float val;
};
template …Run Code Online (Sandbox Code Playgroud) 摆弄编译器资源管理器(以及在 std::optional 上阅读 cppref.com)半小时后,我放弃了。除了我不明白为什么这段代码不能编译之外,没有什么可说的。有人请解释这一点,如果有的话,也许可以告诉我一个解决方法?std::optional我在这里使用的所有成员函数都是constexpr,并且确实应该在编译时可计算,因为这里的可选类型 - size_t- 是原始标量类型。
#include <type_traits>
#include <optional>
template <typename T>
[[nodiscard]] constexpr std::optional<size_t> index_for_type() noexcept
{
std::optional<size_t> index;
if constexpr (std::is_same_v<T, int>)
index = 1;
else if constexpr (std::is_same_v<T, void>)
index = 0;
return index;
}
static_assert(index_for_type<int>().has_value());
Run Code Online (Sandbox Code Playgroud)
我需要运行一个带有 N 个布尔变量的函数,我想让它们 constexpr 以消除比较并从分支预测失败中保存代码。
我的意思是:
templateFunc<b1, b2, b3, b4 ...>(args...);
Run Code Online (Sandbox Code Playgroud)
由于 b1..bn 变量只是布尔变量并且可能只有 2 个状态,我可以这样写:
if (b1 && b2)
templateFunc<true, true>(args...);
else if (b1 && !b2)
templateFunc<true, false>(args...);
else if (!b1 && b2)
templateFunc<false, true>(args...);
else
templateFunc<false, false>(args...);
Run Code Online (Sandbox Code Playgroud)
问题很明显,我需要对 5 个变量进行 64 次调用。有什么解决方案吗?
c++ templates variadic-templates constexpr branch-prediction
constexpr ×10
c++ ×9
c++17 ×4
templates ×4
c++11 ×3
c++20 ×2
algorithm ×1
arrays ×1
c++14 ×1
clang ×1
dereference ×1
enums ×1
if-constexpr ×1
iterator ×1
stdoptional ×1