GCC、LLVM 和 MSVC 不同意将 constexpr std::string 的内容传递给运行时世界。谁是对的?

问题描述 投票:0回答:1

我试图在编译时创建一个

std::string
并将其内容传递到运行时世界。与此同时,我偶然发现了这个问题:

#include <algorithm>
#include <string>

template <std::size_t N>
struct ct_to_rt_string {
    consteval ct_to_rt_string(std::string const str) {
        std::copy_n(str.c_str(), N + 1, buffer);
    }

    char buffer[N + 1];
};

constexpr std::string make_ct_std_string() {
    return "compile time text";
}

#include <iostream>

int main() {
    std::cout << ct_to_rt_string<make_ct_std_string().size()>(make_ct_std_string()).buffer;
}

带有 libstdc++ 的 GCC 12.2 编译并给出预期的输出:

compile time text

带有 libc++ 的 LLVM 16 抱怨不是常量表达式因为没有释放内存:

<source>:20:34: error: non-type template argument is not a constant expression
    std::cout << ct_to_rt_string<make_ct_std_string().size()>(make_ct_std_string()).buffer;
                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-16.0.0/bin/../include/c++/v1/__memory/allocator.h:113:38: note: allocation performed here was not deallocated
            return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
                                     ^
1 error generated.
ASM generation compiler returned: 1
<source>:20:34: error: non-type template argument is not a constant expression
    std::cout << ct_to_rt_string<make_ct_std_string().size()>(make_ct_std_string()).buffer;
                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-16.0.0/bin/../include/c++/v1/__memory/allocator.h:113:38: note: allocation performed here was not deallocated
            return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
                                     ^
1 error generated.

MSVC 19.35 抱怨构造函数不是 常量表达式

<source>(20): error C7595: 'ct_to_rt_string<17>::ct_to_rt_string': call to immediate function is not a constant expression

三个编译器哪个是对的?

c++ c++20 constexpr stdstring consteval
1个回答
0
投票

我认为gcc是正确的。具体来说,clang 很乐意编译它(并且它运行正确):

int main() {
    constexpr size_t N = make_ct_std_string().size();
    std::cout << ct_to_rt_string<N>(make_ct_std_string()).buffer;
}

演示

所以我想归结为用于评估模板参数的对象的生命周期何时被视为结束,正如@user17732522 指出的那样。

FWIW,它也会编译这个:

int main() {
    std::cout << ct_to_rt_string<17>(make_ct_std_string()).buffer;
}

MSVC,然而,仍然不会编译这段代码:https://godbolt.org/z/vdaKcaqY6

© www.soinside.com 2019 - 2024. All rights reserved.