clang++ 12是否支持C++20的std::construct_at?

5

我正在尝试使用最近批准的C++20标准特性std::construct_at(),并试图更加熟悉它们...

我基于CppReference.com的示例构建了一个示例:

#include <memory>

struct S {
    int a;
    int b;
};

int main() {
    std::allocator<S> alloc;
    S * s = alloc.allocate(1);
    std::construct_at(s, 42, 43); // GCC 10.2 OK Clang 12 NOT
    std::destroy_at(s);
    alloc.deallocate(s, 1);
    s = nullptr;
}

使用最新稳定版GCC,上述代码可以成功编译: gcc-10.2 test.cpp -std=c++2a -lstdc++

但是我无法在Clang 12 (trunk)或10 (stable)中编译它。 clang-12 test.cpp -std=c++20 -stdlib=libc++ 出现错误:

test.cpp:11:5: error: no matching function for call to 'construct_at'
    std::construct_at(s, 42, 43); // GCC 10.2 OK Clang 12 NOT
    ^~~~~~~~~~~~~~~~~
/usr/local/clang/bin/../include/c++/v1/memory:903:16: note: candidate template ignored: substitution failure [with _Tp = S, _Args = <int, int>]: no matching constructor for initialization of 'S'
constexpr _Tp* construct_at(_Tp* __location, _Args&& ...__args) {
               ^
1 error generated.

我是否错误地使用了参数包? Clang C++20 功能列表似乎尚未支持? 我已经尝试使用GCC工具链在Clang中进行编译,结果相同:--gcc-toolchain=/usr/local/gcc-10.2.0 我在在线编译器探索器中也遇到了类似的问题。
如果我通过初始化列表显式构造S(这可能会破坏原地构造的目的)std::construct_at(s, S{42, 43});,那么程序将编译但链接失败。
这种方法是否构造了一个临时对象,从而破坏了construct_at的目的? 如果我加上一个std::move会怎样?std::construct_at(s, std::move(S{42, 43}));在线编译器探索器似乎表明需要更多的汇编代码来移动,也许没有它会有省略(并且我通过添加移动创建了一种悲观情况)?
链接错误为:
/usr/bin/ld: /tmp/test-b07239.o: in function `std::__1::__throw_length_error(char const*)':
test.cpp:(.text._ZNSt3__120__throw_length_errorEPKc[_ZNSt3__120__throw_length_errorEPKc]+0x12): undefined reference to `__cxa_allocate_exception'
/usr/bin/ld: test.cpp:(.text._ZNSt3__120__throw_length_errorEPKc[_ZNSt3__120__throw_length_errorEPKc]+0x30): undefined reference to `typeinfo for std::length_error'
/usr/bin/ld: test.cpp:(.text._ZNSt3__120__throw_length_errorEPKc[_ZNSt3__120__throw_length_errorEPKc]+0x3a): undefined reference to `std::length_error::~length_error()'

显然,-stdlib=libc++ 应该与ABI一起使用-lstdc++可以解决链接错误,而-lc++abi仍然存在问题:

/usr/bin/ld: /tmp/test-bb0950.o: in function `std::length_error::length_error(char const*)':
test.cpp:(.text._ZNSt12length_errorC2EPKc[_ZNSt12length_errorC2EPKc]+0x23): undefined reference to `std::logic_error::logic_error(char const*)'

我是否还缺少逻辑错误的另一个库?

回到关键问题:

  • Clang是否支持std::construct_at(s, 42, 43);
  • 使用初始化列表构造会有性能损失吗?带/不带移动操作?

很少有人可以访问clang++ 12(我自己只有9),如果您尝试使用语言中的_HEAD_功能,将会发生变化。 - Ted Lyngmo
1个回答

8
这与construct_at无关。 S是一个聚合体; 除了默认构造函数和复制/移动构造函数之外,它没有其他可调用的构造函数。因此,只能通过聚合初始化使用值来构造S
通常需要使用花括号初始化列表(例如:S{3,5})。但是C++20包括一项功能,允许通过构造函数语法(例如:S(3,5))进行聚合初始化,只要参数不调用默认或复制/移动构造函数(在这种情况下,将调用其中之一)。
但是,截至目前,Clang 尚未实现该功能。因此,construct_at无法构造该聚合体。

我喜欢人们现在就了解这些东西!"std :: construct_at(s,42,43); //GCC 10.2 OK Clang 12 NOT" +1 - Ted Lyngmo
1
相关参考资料可能是:P0960R3 - François Carouge
从现代C++创新的前沿开始,Clang/libc++的开发似乎最近有些停滞不前。它仍然缺乏完整的C+17支持,甚至在C++20方面也远远落后。一年前就有关于C++20的PR,但似乎没有人关注。我想知道是否适当的概念支持将使这些问题更易于理解,即使对于不太熟悉的人也是如此。 - Zingam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接