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

Posted

技术标签:

【中文标题】MSVC 19.11 / Visual C++ 2017:大小为 1 和 size_t 类型的初始值设定项列表被误解【英文标题】:MSVC 19.11 / Visual C++ 2017: initializer list of size 1 and size_t type misinterpreted 【发布时间】:2017-09-21 13:35:54 【问题描述】:

使用 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;

命令和编译器:

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\

【问题讨论】:

也可能是库错误 - 似乎它选择了 vector::vector(size_t count) 构造函数。 我想知道这是否与N3922有关。如果您使用 value ,它确实可以正常工作。 我认为我们可以简化。 int test( std::size_t ) return 1; int test( std::initializer_list&lt;std::size_t&gt; ) return 2; ;我们有 test(7u) 更喜欢 size_t 重载而不是 il 重载。 不,不一样; 19.00 通过了test(7ull),但仍然中断了上述代码。发生了一些有趣的事情。 【参考方案1】:

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

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

#include <initializer_list>
#include <cstddef>

struct V 
    size_t sz;
    constexpr V(size_t s)  sz = s;  
    constexpr V(std::initializer_list<int> l)  sz = l.size(); 
;

static_assert( V(size_t(3)).sz == 1 );

这里 struct V 模仿 std::vector 及其两个有问题的构造函数。

根据over.ics.rank#3.1

列表初始化序列 L1 是比列表初始化序列 L2 更好的转换序列,如果 (3.1.1) 对于某些 X,L1 会转换为 std​::​initializer_list 而 L2 不会...

所以在这个例子中V(size_t(3)) 应该调用构造函数V(std::initializer_list&lt;int&gt; l),它在 GCC 和 Clang 中这样做,但在 MSVC 中没有。演示:https://gcc.godbolt.org/z/3q64f7Yr7

MSVC 错误报告:https://developercommunity.visualstudio.com/t/Wrong-constructor-of-std::vector-selecte/1652923

【讨论】:

以上是关于MSVC 19.11 / Visual C++ 2017:大小为 1 和 size_t 类型的初始值设定项列表被误解的主要内容,如果未能解决你的问题,请参考以下文章

MSVC10 Visual Studio 2010 是不是支持 C++ 显式转换运算符

vscode使用visual studio编译工具MSVC构建C++工程

vscode使用visual studio编译工具MSVC构建C++工程

msvc visual c++从静态成员函数中不正确地形成绑定成员函数表达式

Visual C++ 和 gcc 一样强大吗?

Microsoft Visual C++ 的 Makefile