繁体   English   中英

即使初始化条件通过 static_assert 变量也不是 constexpr

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM