[英]Variable not constexpr even though initialization condition passes static_assert
我正在尝试编写一些编译时字符串组合功能。 如果您在末尾注释掉代码部分,则以下代码将编译。
#include <iostream>
constexpr const char a[] = "hello ";
constexpr const char b[] = "dear ";
constexpr const char c[] = "world!";
constexpr size_t size(const char* s)
{
int i = 0;
while(*s!=0) {
++i;
++s;
}
return i;
}
template <typename... Is, typename = std::enable_if_t<(... && std::is_same_v<const char*, Is>)>>
constexpr size_t calc_size(Is... values) {
return (0 + ... + size(values));
}
constexpr bool strings_equal(char const * a, char const * b) {
return *a == *b && (*a == '\0' || strings_equal(a + 1, b + 1));
}
template <const char*... S>
class cxpr_string
{
public:
constexpr cxpr_string() : buf_{}, size_{0} {
int i=0;
( [&]() {
const size_t max = size(S);
for (int i=0; i < max; ++i) {
buf_[size_++] = S[i];
}
}(), ...);
buf_[size_++] = 0;
}
constexpr const char* get() const {
return buf_;
}
private:
char buf_[calc_size(S...)+1] = { 0 };
size_t size_;
};
template <const char*... ptr>
constexpr auto joined = cxpr_string<ptr...>().get();
int main()
{
static_assert(strings_equal(cxpr_string<a,b,c>().get(), "hello dear world!"));
std::cout << joined<a,b,c> << std::endl; // <-- Why not constexpr?? (comment this out)
std::cout << cxpr_string<a, b, c>().get() << std::endl;
}
但是,如果您不这样做,则会收到以下错误:
<source>: In instantiation of 'constexpr const char* const joined<(& a), (& b), (& c)>':
<source>:56:18: required from here
<source>:50:16: error: '(const char*)(&<anonymous>.cxpr_string<(& a), (& b), (& c)>::buf_)' is not a constant expression
50 | constexpr auto joined = cxpr_string<ptr...>().get();
| ^~~~~~
这对我来说非常令人惊讶,因为 cxpr_string 类的完全相同的应用程序用于初始化有问题的变量传递了 static_assert! 也存在编译器差异:它不能在 gcc 12.1 和 clang 14.0.0 中编译,但它在 msvc 19.31 中编译(但失败)。
我错过了什么?
这是一个更友好、更温和的问题再现。
Clang 会告诉你问题是什么。 “指向临时子对象的指针不是常量表达式”。 确实,你想joined
指向哪里?
constexpr 变量必须由常量表达式初始化,而foo().get()
不是。 然而,它是一个核心常量表达式。 的确:
表达式 E 是核心常量表达式,除非按照抽象机 (6.9.1) 的规则对 E 的求值将求值以下之一:
- [...]
- 左值到右值的转换(7.3.1),除非它应用于
- [...]
- 文字类型的非易失性左值,它引用一个非易失性对象,其生命周期在 E 的评估中开始
然而
常量表达式或者是指代作为常量表达式(如下定义)的允许结果的实体的泛左值核心常量表达式,或者是其值满足以下约束的纯右值核心常量表达式:
- [...]
- 如果该值是指针类型,则它包含具有静态存储持续时间的对象的地址、超过此类对象末尾的地址 (7.6.6)、非立即函数的地址或空指针值
我想可以将核心常量表达式传递给 constexpr 函数,结果可能是(但不总是)一个完全诚实的常量表达式,适合初始化 constexpr 变量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.