26

该程序在使用 VC12(在 Visual Studio 2013 RTM 中)[1]编译时会导致崩溃(在所有构建配置中),而实际上它不应该:

#include <string>

void foo(std::string const& oops = {})
{
}

int main()
{
    foo();
}

我知道两个可能相关的无声的错误代码生成错误:

不过,老实说,我认为这些是不同的。有人知道吗

  1. 连接上是否存在主动跟踪的错误
  2. 是否有解决方法(或对导致此错误的情况的明确描述,以便我们可以在代码库中查找/避免它)?

[1]只需使用 C++ 控制台应用程序“向导”创建一个空项目。为简单起见,禁用预编译头并保留所有默认值:http: //i.stack.imgur.com/rrrnV.png

4

2 回答 2

11

当默认参数是初始值设定项列表时,它调用的构造函数似乎Visual Studio只是被破坏了。这段代码:

#include <iostream>

struct test {
  test ()  { std::cout << "test ()" << std::endl ; } 
  test (int)  { std::cout << "test (int)" << std::endl ; }
};

void func( test const &s = {} )
{
}

int main()
{
    test s = {} ;
    func() ;
}

gcc在and中产生这个结果,在这里clang看到它:

test ()
test ()

Visual Studio产生这个结果:

test ()
test (int)

对于这段代码:

#include <iostream>
#include <initializer_list>

struct test {
  test ()  { std::cout << "test ()" << std::endl ; };

  test (int)  { std::cout << "test (int)" << std::endl ; };
  test ( std::initializer_list<int>) { std::cout << "test (initializer_list<int>)" << std::endl ; } ;
};

void func( test const &s = {0} )
{
}

int main()
{
    test s = {0} ;
    func() ;
}

gccclang产生这个结果在这里看到它:

 test (initializer_list<int>)
 test (initializer_list<int>)

Visual Studio产生此错误:

 error C2440: 'default argument' : cannot convert from 'initializer-list' to 'const test &'
    Reason: cannot convert from 'initializer-list' to 'const test'
    No constructor could take the source type, or constructor overload resolution was ambiguous

更新

为了进行完整性检查,我回到了标准,以确保这种差异的根源没有一些奇怪的规则,或者可能是一些使这段代码格式错误的限制。据我所知,这段代码不是格式错误的。节8.3.5语法特别允许这样做:

parameter-declaration:
  attribute-specifier-seqopt decl-specifier-seq declarator
  attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
  [...]

似乎8.5 初始化程序或8.3.6 默认参数部分没有添加任何限制,但此缺陷报告994.braced-init-list 作为默认参数和工作文件将大括号初始化器作为默认参数的措辞清楚地表明它是有意的并概述了更改符合标准以允许它并查看增量没有明显的限制。

于 2014-01-10T15:44:43.840 回答
8

11 月发布了一个活跃的问题。发布的示例代码是:

Compile and run following code in VS2013

#include <string>

void f(std::string s = {}) {
}

int main(int argc, char* argv[]) {
    f();
    return 0;
}

微软已经承认了这个错误。

那里似乎没有发布解决方法。编辑变通方法可以很容易地基于避免列表初始化器语法:

void f(std::string s = "");
void f(std::string s = std::string());
void f(std::string s = std::string {});

或者只是老式的(如果你不介意引入重载):

void f(std::string s);
void f() { f(std::string()); }
于 2014-01-10T13:03:24.273 回答