Luk*_*rth 16 c++ visual-c++ language-lawyer c++20
我目前正在尝试在 C++20 下构建遗留代码库,我遇到了这样的事情:
\nsize_t someCount; // value comes from somewhere else\n\xe2\x80\xa6\nstd::vector<const char *[2]> keyValues(someCount);\nRun Code Online (Sandbox Code Playgroud)\n我不能轻易地将其更改为类似的内容,std::vector<std:array<const char *, 2>>因为它稍后会传递给我无法控制的某个 API。只要我不启用 C++20,上述令人厌恶的内容就可以在 Clang 和 GCC 甚至 MSVC 中正常编译,但它会在 C++20 中的 MSVC 中中断,正如您在Godbolt 中看到的那样。
我认为这与是否使用上述构造函数的DefaultInsertable要求有关(这实际上是标准强制执行的T唯一要求)。根据 cppreference(请参阅前面的链接),C++17 之前的 STL 实现使用放置 new 来默认构造元素,从 C++20 开始,用于类型。这可能会触发 MSVC 从 C++17 回归到 C++20。std::construct_atDefaultInsertable
该标准规定,DefaultInsertable如果该表达式格式良好,则为类型:
allocator_traits<A>::construct(m, p)\nRun Code Online (Sandbox Code Playgroud)\n所以就我而言,那就是:
\nconst char * dummy[2];\nusing Allocator = std::allocator<const char *[2]>;\nAllocator a;\n// This must be well-formed:\nstd::allocator_traits<Allocator>::construct(a, dummy);\nRun Code Online (Sandbox Code Playgroud)\n这可以很好地编译,并且在 GCC、Clang 和 MSVC 中不会出现警告,因此我将继续假设它const char *[2]是一种DefaultInsertable类型。但这意味着我的第一个示例中的构造函数调用应该编译。
这是 MSVC 错误吗?
\n编译器错误是:
\nC:/data/msvc/14.34.31931-Pre/include\\xutility(218): error C2440: \'return\': cannot convert from \'const char **\' to \'_Ty (*)\'\n with\n [\n _Ty=const char *[2]\n ]\n\nC:/data/msvc/14.34.31931-Pre/include\\xutility(218): note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or parenthesized function-style cast\nC:/data/msvc/14.34.31931-Pre/include\\xmemory(673): note: see reference to function template instantiation \'_Ty (*std::construct_at<_Objty,,0x0>(_Ty (*const )) noexcept)\' being compiled\n with\n [\n _Ty=const char *[2],\n _Objty=const char *[2]\n ]\nRun Code Online (Sandbox Code Playgroud)\n
use*_*522 14
在 C++20 之前,不支持在std::vector默认分配器中使用数组类型,因为会尝试一个简单的(伪)析构函数调用,该调用对于除类和标量类型之外的任何类型都是格式错误的。因此,数组类型不满足默认分配器的可擦除要求,而这需要满足。std::allocatorstd::allocator::destroystd::vector
由于 C++20std::allocator默认std::allocator_traits使用 use ,std::destroy_at因此数组类型有一个特殊情况,即在每个元素上单独调用析构函数。所以Erasable现在对默认分配器感到满意。
然而,C++20 也std::allocator默认construct通过std::allocator_traits使用std::construct_at. 与旧的相反std::allocator::construct,std::construct_at返回placement-new表达式的结果,并将其返回类型声明为而T*不是void。T*也是第一个参数的类型,即T元素类型。
这里的问题是,里面的placement-new表达式std::construct_at不会返回数组类型的数组指针,而是返回指向数组第一个元素的指针。如果T是数组类型U[N],则 new 表达式的返回类型是U*,而不是U(*)[N]声明construct_at返回的类型。因此,construct_at实例化的格式不正确,并且数组类型不满足默认分配器的DefaultInsertable要求。
这可能是无意的,std::construct_at不适用于有界数组类型。为此有一个开放的LWG 问题 3436 。
| 归档时间: |
|
| 查看次数: |
940 次 |
| 最近记录: |