2013-04-07 4 views
3

Может ли кто-нибудь сказать мне теорию этого?Конструктор и initializer_list

Почему последний звонок не компилируется?

test.cc: In function ‘int main()’: test.cc:15:12: error: too many braces around initializer for ‘int’ [-fpermissive] test.cc:15:12:

error: invalid conversion from ‘’ to ‘int’ [-fpermissive] test.cc:9:6: error: initializing argument 1 of ‘void f(std::initializer_list)’ [-fpermissive] test.cc:15:12:

error: aggregate value used where an integer was expected

Я думаю, что на этом сломается либо C++ 11, либо g ++ 4.7. Спасибо!

#include <initializer_list> 

class A { 
    public: 
    A(const std::initializer_list<int>) {} 
}; 

void f(const std::initializer_list<int>) {} 

int main() { 
    A({1}); // Compile OK 
    f({1}); // Compile OK 
    A({{{1}}}); // Compile OK 
    //f({{{1}}}); // Compile Error. 
} 
+0

Спасибо. Я говорю об заголовке initializer_list stardard в C++ 11. – yufanyufan

+0

Интересно. В обоих случаях Clang просто предупреждает о дополнительных фигурных скобках. – soon

ответ

2

Вот что я считаю, что GCC думает.

Это ваша программа с 1 дополнительной строкой, а интересные строки пронумерованы.

int main() { 
    A({1}); // 1. Compile OK 
    f({1}); // 2. Compile OK 
    A{{1}}; // 3. Compile OK, equivalent to 1. 
    A({{{1}}}); // 4. Compile OK 
    //f({{{1}}}); // 5. Compile Error. 
} 

Почему GCC составляет 4, но не 5?

Для наглядности предположим, что строительство на # 4 на самом деле заявленную что-то:

A a{{{1}}}; // 4a. Compile OK 

GCC спрашивает, если аргумент конструктора, который {{1}} является неявно конвертируются в A. Так:

A{{1}} 

действительный переход от {{1}} к A? Да, это - по 3.

Это рассуждение, конечно, не относится к № 5; следовательно, ошибка.

Если вы хотите, чтобы остановить GCC от принятия # 4, а затем блокировать , позволяющее преобразование, делая стимулирующий конструктор явный:

class A { 
    public: 
    explicit A(const std::initializer_list<int> il) {} 
}; 

Тогда # 4 будут давать ошибку:

error: converting to ‘A’ from initializer list would use explicit constructor ‘A::A(std::initializer_list<int>)’ 
+0

Я заметил, что f ({1}) и f ({{1}}) компилируются без ошибок. в чем разница между ними? – yufanyufan

+0

Мой неуклюжий отчет о преобразовании конструктора из '{{1}}' попадает на борт где-то, но Йоханнес получает сигару. Я думаю, что его слова «второй идет в список инициализаторов рекурсивно.« , вероятно, также объясняет, почему' f ({{1}}) 'ОК, но я буду откладывать на него это. –

+0

Первая скобка для списка инициализации. Вторая фигурная скобка для int. –

2

A {1} может инициализировать int. A {{1}}, вероятно, не должен - для этого есть отчет о дефекте для комитета. GCC запрещает это, и clang просто имеет тенденцию выдавать предупреждения о резервных скобках в настоящее время.

Когда X является классом, который имеет объекты копирования или перемещения, то X ({...}) может ссылаться на один из них. Обратите внимание, что X {...} может тоже, но ограничено, чтобы не допускать определенных пользователем преобразований (для копирования или перемещения конструктора).

Теперь с вашим A ({{{1}}}) первая скобка потребляется конструктором copy/move. Второе идет рекурсивно. И третий идет к содержащему int.

Согласно Стандарту, для A ({{{{1}}}}) будет добавлена ​​еще одна скобка. Поскольку вторая фигурная скобка должна потребляться конструктором copy/move A, но для нее требуется определенная пользователем последовательность преобразования. То же самое справедливо и для A {{{{}}}}}, что также неверно по этой причине.

Смежные вопросы