MSVC 19.11 / Visual C++ 2017:大小为 1 和 size_t 类型的初始值设定项列表被误解

tot*_*ing 5 c++ visual-c++ language-lawyer compiler-bug c++11

使用 MSVC 19.11 编译以下代码会产生输出

With 32: 0 99 2 With 64: 0 1 2使用 32 位编译器,并在

With 32: 0 1 2 With 64: 0 99 2使用 64 位编译器。

问题是单个元素初始值设定项列表的类型恰好是size_t。这是一个编译器错误(到目前为止我还没有发现它在任何地方报告过),而不是标准不明确的情况(clang 和 gcc 都没有这个问题)?

#include <cstdint>
#include <vector>
#include <iostream>

int main() {
    using T = std::uint16_t;
    // fixed with uint32 / uint64 on 32 / 64 bit compilers, respectively,
    // but not with int32_t / int64_t
    {
        std::vector<T> s0;
        //  std::vector<T> s1{ 99u }; // OK
        //  std::vector<T> s1 = { 99u }; // OK
        std::vector<T> s1( { 99u } ); // BUG?
 // EDIT: std::vector<T> s1( {{ 99u }} ); // also OK
        std::vector<T> s2( { 40u, 70u } );
        std::cout << "With " << sizeof(0u)*8 << ':' << ' '
          << s0.size() << ' ' << s1.size() << ' ' << s2.size() << '\n';
    }

    {
        std::vector<T> s0;
        std::vector<T> s1( { 99ull } );
        std::vector<T> s2( { 40ull, 70ull } );
        std::cout << "With " << sizeof(0ull)*8 << ':' << ' '
          << s0.size() << ' ' << s1.size() << ' ' << s2.size() << '\n';
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

命令和编译器:

cl.exe ilist.cpp & .\ilist.exe   # no extra cl arguments

cl.exe
Microsoft (R) C/C++ Optimizing Compiler Version 19.11.25507.1 for x64
Copyright (C) Microsoft Corporation.  All rights reserved. (or x86)

x64\cl.exe and x86\cl.exe from
...\Tools\MSVC\14.11.25503\bin\HostX64\
Run Code Online (Sandbox Code Playgroud)

Fed*_*dor 1

是的,这是 Visual Studio 编译器错误。

\n

一个更简单的例子来说明问题:

\n
#include <initializer_list>\n#include <cstddef>\n\nstruct V {\n    size_t sz;\n    constexpr V(size_t s) { sz = s; } \n    constexpr V(std::initializer_list<int> l) { sz = l.size(); }\n};\n\nstatic_assert( V({size_t(3)}).sz == 1 );\n
Run Code Online (Sandbox Code Playgroud)\n

这里struct V模仿了std::vector它的两个构造函数。

\n

根据over.ics.rank#3.1

\n
\n

列表初始化序列 L1 是比列表初始化序列 L2 更好的转换序列,如果\n(3.1.1)\nL1 对于某些 X 转换为 std\xe2\x80\x8b::\xe2\x80\x8binitializer_\xc2\xadlist而L2不...

\n
\n

所以在这个例子中V({size_t(3)})应该调用构造函数V(std::initializer_list<int> l),它在GCC和Clang中这样做,但在MSVC中则不然。演示: https: //gcc.godbolt.org/z/3q64f7Yr7

\n

此 MSVC 错误已在 Visual Studio 2022 版本 17.9 中修复:https://developercommunity.visualstudio.com/t/Wrong-constructor-of-std::vector -selecte/1652923

\n