(Известная) ошибка компилятора в VC12?
Эта программа, скомпилированная с VC12 (в RTM RTU), [1] приводит к сбою (во всех конфигурациях сборки), когда это действительно не должно:
#include <string>
void foo(std::string const& oops = {})
{
}
int main()
{
foo();
}
Я знаю о двух молчащих ошибках badegegen, которые связаны с может:
Честно говоря, я думаю, что это разные. Кто-нибудь знает
- есть ли активная отслеживаемая ошибка для подключения для этого
- существует ли способ обхода (или явное описание ситуации, которая вызывает эту ошибку, поэтому мы можем ее искать/избегать в нашей базе кода)?
[1] Просто создайте пустой проект, используя мастер-приложение консоли С++. Для простоты отключите предварительно скомпилированные заголовки и оставьте все значения по умолчанию: http://i.stack.imgur.com/rrrnV.png
Ответы
Ответ 1
Активная проблема была опубликована в ноябрь. Проведенный пример кода:
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()); }
Ответ 2
Похоже, что 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 ()
while 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 как аргумент по умолчанию и рабочий документ Формулировка для инициализаторов символов в качестве аргументов по умолчанию дает понять, что это было предназначено и наметить изменения, внесенные в стандарт, чтобы позволить это и глядя на дельт, нет очевидных ограничений.