可以通过 clang 或 gcc 的命令行选项配置 constexpr 编译时递归限制吗?如何?
在尝试找出为什么会出现某个编译错误时,我想出了以下最小示例:
\n\nconstexpr void Test(bool test)\n{\n if (test)\n return;\n\n assert(false);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n我尝试过的每个版本的 clang (3.7+) 都可以毫无问题地进行编译,但使用 gcc 会失败(测试了 5-8),
\n\n\n\n\n错误:调用非\xe2\x80\x98constexpr\xe2\x80\x99函数\xe2\x80\x98void __assert_fail(const\n char*, const char*, unsigned int, const char*)\xe2\x80\x99
\n
根据我的理解,该函数应该能够constexpr,因为可以在编译时评估该函数的一组参数值。
是我的理解错误,还是gcc编译失败而错误?
\n查看的实现std::is_same我们可以看到一些内部函数(继承自integral_constant)。为方便起见,让我复制 g++ 代码:
template<typename _Tp, _Tp __v>
struct integral_constant {
static constexpr _Tp value = __v;
typedef _Tp value_type;
typedef integral_constant<_Tp, __v> type;
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};
template<typename, typename>
struct is_same : public integral_constant<bool, false> { };
template<typename _Tp>
struct is_same<_Tp, _Tp> : public integral_constant<bool, true> { };
Run Code Online (Sandbox Code Playgroud)
这为我们提供了如何使用它的几个选项:
bool a1 = is_same<int, int>{}; // instantiate & then cast implicitly
bool …Run Code Online (Sandbox Code Playgroud) 我听说这std::bit_cast将在 C++20 中实现,我对实现它必然需要特殊编译器支持的结论感到有些困惑。
公平地说,我听到的论点是实现执行了一个memcpy操作,并且memcpy通常不是constexpr,而std::bit_cast应该是,因此制作std::bit_cast constexpr据称需要编译器支持constexpr兼容的memcpy操作。
但是,我想知道是否有可能在根本不实际调用的情况下实现合规bit_cast(即定义的行为,其程度与 usingmemcpy具有定义的行为相同)memcpy。
考虑以下代码:
template<typename T, typename U>
inline constexpr T bit_cast(const U & x) noexcept {
static_assert(std::is_trivial<T>::value && std::is_trivial<U>::value, "Cannot use bit_cast with non-trivial data" );
static_assert(sizeof(T) == sizeof(U), "bit_cast must be used on identically sized types");
union in_out {
volatile U in;
volatile T out;
inline constexpr explicit in_out(const U &x) noexcept …Run Code Online (Sandbox Code Playgroud) 我试图查看由 g++ 编译的 cpp constexpr 函数的编译代码。我看到,如果该函数不返回任何内容,编译器将其视为常规函数,但如果它返回一个值并且我将此值分配给 constexpr 变量,则仅在编译时计算它。
代码示例:
constexpr int func(int x){
return x!=0 ? 1: throw "Error";
}
int main(){
func(2);
}
Run Code Online (Sandbox Code Playgroud)
和编译器输出:
push rbp
mov rbp, rsp
mov edi, 2
call func(int)
mov eax, 0
pop rbp
ret
Run Code Online (Sandbox Code Playgroud)
如您所见,它在运行时调用 func。相反,如果我将函数结果赋值给 constexpr:
constexpr int func(int x){
return x!=0 ? 1: throw "Error";
}
int main(){
constexpr int x = func(2);
}
Run Code Online (Sandbox Code Playgroud)
和编译器输出:
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 1
mov eax, 0
pop rbp …Run Code Online (Sandbox Code Playgroud) 试图创建一个能够重新解释 IEEE 双精度位的 constexpr 类。例子:
constexpr double pi = 3.14159265358979323846;
constexpr fixedpoint a(pi);
Run Code Online (Sandbox Code Playgroud)
但是,遇到了 reinterpret_cast 不是常量子表达式的问题。
我在 constexpr fixedpoint& operator=(double rhs) 中使用它:
Run Code Online (Sandbox Code Playgroud)uint64_t fraction = *reinterpret_cast<const uint64_t*>(&rhs) & 0x000F'FFFF'FFFF'FFFFull;
但编译器将该语句标记为非常量子表达式。
尝试了类型双关语,但遇到了在 C++ 中只有一个字段可以处于活动状态的约束。
任何人都有一种解决方案,可以让我重新解释有效 constexpr 代码的 double 位?
constexpr 函数的标准在[decl.constexpr] 的第 5 点下说明:
对于非模板、非默认的 constexpr 函数或非模板、非默认、非继承的 constexpr 构造函数,如果不存在参数值使得函数或构造函数的调用可以是核心常量的计算子表达式表达式 (5.19),程序格式错误;无需诊断。
它继续为此提供以下示例:
constexpr int f(bool b){ return b ? throw 0 : 0; } // OK
constexpr int f() { return f(true); } // ill-formed, no diagnostic required
Run Code Online (Sandbox Code Playgroud)
我从中得到的是,带有空参数列表的函数是非诊断格式错误的。这让我觉得非常奇怪,以至于我怀疑我的理解是不正确的。例如,这是否也是格式错误的:
constexpr int g() { return 0; } // ill-formed?
Run Code Online (Sandbox Code Playgroud)
如果是这样,这背后的基本原理是什么,如果不是,则限定意味着什么/ constexpr 函数何时变得格式错误?
想必以下这些都可以吧?
constexpr int h(int x) { return x; } // presumably fine?
constexpr int l = h(42); // also fine
Run Code Online (Sandbox Code Playgroud) 我们如何在编译时动态分配?是否constexpr operator new只是在栈上分配内存?
我知道需求的差异,我最感兴趣的是它带来的代码质量带来的好处。
我能想到的几件事:
constevalfns 在运行时从不使用(这是推测性的,我没有这方面的真实数据)注意:如果代码质量太模糊,我理解有些人可能想要结束这个问题,对我来说代码质量并不是那么模糊的术语,但是......
例如,其中constexpr故障被延迟到运行时:
constexpr int div_cx(int a, int b)
{
assert(b!=0);
return a/b;
}
int main()
{
static constexpr int result = div_cx(5,0); // compile time error, div by 0
std::cout << result;
std::cout << div_cx(5,0) ; // runtime error :(
}
Run Code Online (Sandbox Code Playgroud) 用下面的代码,我得到Constexpr variable 'max_digits' must be initialized by a constant expression与Apple clang version 12.0.5 (clang-1205.0.22.11)运行C ++ 14。
不过,如果我#define WORKING_CODE它正常工作与base_two_digits是一个全球性的功能。如果我将 的内容移动base_two_digits到log_base_10,我会得到一个错误(这是出现的时候#undef WORKING_CODE)。
为什么不是constexpr,如果WORKING_CODE未定义?
#include <limits>
#include <cstdint>
#include <cmath>
template<typename T>
constexpr T power_of_10(T n)
{
return n < 0 ? 0 : n == 0 ? 1 : (n == 1 ? 10 : 10 * power_of_10(n - 1));
}
#ifdef WORKING_CODE
constexpr …Run Code Online (Sandbox Code Playgroud)