Consider this short program compiled with GCC 4.7.2 g++ -std=c++11 test.cc
#include <memory>
#include <queue>
struct type{
type(int a) : v(a) {}
int v;
};
typedef std::shared_ptr<type> type_ptr;
int main(){
int value = 3;
std::queue<type_ptr> queue;
auto ptr{std::make_shared<type>(value)};
queue.push(ptr);
}
The compiler outputs the following errors:
src/test.cc: In function ‘int main()’:
src/test.cc:15:17: error: no matching function for call to ‘std::queue<std::shared_ptr<type> >::push(std::initializer_list<std::shared_ptr<type> >&)’
src/test.cc:15:17: note: candidates are:
In file included from /usr/include/c++/4.7/queue:65:0,
from src/test.cc:2:
/usr/include/c++/4.7/bits/stl_queue.h:211:7: note: void std::queue<_Tp, _Sequence>::push(const value_type&) [with _Tp = std::shared_ptr<type>; _Sequence = std::deque<std::shared_ptr<type>, std::allocator<std::shared_ptr<type> > >; std::queue<_Tp, _Sequence>::value_type = std::shared_ptr<type>]
/usr/include/c++/4.7/bits/stl_queue.h:211:7: note: no known conversion for argument 1 from ‘std::initializer_list<std::shared_ptr<type> >’ to ‘const value_type& {aka const std::shared_ptr<type>&}’
/usr/include/c++/4.7/bits/stl_queue.h:216:7: note: void std::queue<_Tp, _Sequence>::push(std::queue<_Tp, _Sequence>::value_type&&) [with _Tp = std::shared_ptr<type>; _Sequence = std::deque<std::shared_ptr<type>, std::allocator<std::shared_ptr<type> > >; std::queue<_Tp, _Sequence>::value_type = std::shared_ptr<type>]
/usr/include/c++/4.7/bits/stl_queue.h:216:7: note: no known conversion for argument 1 from ‘std::initializer_list<std::shared_ptr<type> >’ to ‘std::queue<std::shared_ptr<type> >::value_type&& {aka std::shared_ptr<type>&&}’
Indicating that the auto type is expanded to an initializer list instead of std::shared_ptr<type>
; in fact replacing {...}
with = ...
makes the code compile as auto expands to the correct type.
I'm a bit suprised that this seemingly obvious use case fails to achieve the expected result. Especially as I recall the new bracket initialization syntax to be touted as the end-all, be-all solution to initializing problems.
So my question is: Was this intended in the standard? Or is it an oversight or even a gcc bug? Or am I just thinking about it wrong?
As Xeo says in his comment, this is standard behavior. 7.1.6.4 auto specifier [dcl.spec.auto] para 6 specifies:
Once the type of a declarator-id has been determined according to 8.3, the type of the declared variable using the declarator-id is determined from the type of its initializer using the rules for template argument deduction. Let
T
be the type that has been determined for a variable identifierd
. ObtainP
fromT
by replacing the occurrences ofauto
with either a new invented type template parameterU
or, if the initializer is a braced-init-list (8.5.4), withstd::initializer_list<U>
. The type deduced for the variabled
is then the deducedA
determined using the rules of template argument deduction from a function call (14.8.2.1), whereP
is a function template parameter type and the initializer ford
is the corresponding argument. If the deduction fails, the declaration is ill-formed.
It is also widely despised - there's a proposal under review by the committee to change the behavior for C++14. C++14's support for generalized lambda capture exacerbates the problem.
Update: In Urbana (See CWG Motion 16 in N4251 WG21 2014-11 Urbana Minutes) the committee applied N3922 New Rules for auto deduction from braced-init-list to the C++17 Working Paper. They decided to fix the special case that allows auto
to deduce an initializer_list
by adding another special case. auto
works the same way for copy-list-initialization, but for direct-list-initialization from a braced-init-list with a single element auto
deduces from that element directly. direct-list-initialization from a multiple-element braced-init-list is now ill-formed.
That means that given
auto x = {42};
x
has type std::initializer_list<int>
, but in
auto x{42};
x
is an int
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With