(Известно) ошибка компилятора в VC12?

Эта программа, когда скомпилирована с VC12 (в Visual Studio 2013 RTM)[1] приводит к падению (во всех конфигурациях сборки), когда на самом деле это не должно:

#include <string>

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

int main()
{
foo();
}

Я знаю о двух тихих плохих ошибках в коде может быть связаны:

Честно говоря, я думаю, что они разные, хотя. Кто-нибудь знает

  1. есть ли активно отслеживаемая ошибка на Connect для этого
  2. есть ли обходной путь (или явное описание ситуации, которая вызывает эту ошибку, чтобы мы могли ее искать / избегать в нашей базе кода)?

[1] Просто создайте пустой проект с помощью «мастера» Консольного приложения C ++. Для простоты отключите предварительно скомпилированные заголовки и оставьте все значения по умолчанию: http://i.stack.imgur.com/rrrnV.png

25

Решение

Активная проблема была опубликована в ноябрь. Отправленный пример кода:

Compile and run following code in VS2013

#include <string>

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

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

Ошибка была подтверждена Microsoft.

Похоже, что там нет обходного пути. редактировать Обходные пути могут быть легко основаны на том, чтобы избежать синтаксиса list-initializer:

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()); }
8

Другие решения

Это выглядит как 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 а также 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() ;
}

gcc а также clang произвести этот результат увидеть это живи здесь:

 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 в качестве аргумента по умолчанию и рабочий документ Формулировка скобочных инициализаторов в качестве аргументов по умолчанию дать понять, что это было задумано, и обрисовать в общих чертах изменения, внесенные в стандарт, и, глядя на дельты, нет никаких очевидных ограничений.

11