C ++ Warning: _U1 output as std :: initializer_list <int>
I use g++-4.6.1 --std=c++0x and get a warning that I cannot decrypt with this bit of code:
#include <vector> #include <tuple> int main() { std::tuple<std::vector<int>, int> t{ {1, 2, 3}, 10}; } I get the following warning:
scratch.cpp: In function 'int main()': scratch.cpp:6:55: warning: deducing '_U1' as 'std::initializer_list<int>' [enabled by default] /usr/local/include/c++/4.6.1/tuple:329:9: warning: in call to 'std::tuple<_T1, _T2>::tuple(_U1&&, _U2&&) [with _U1 = std::initializer_list<int>, _U2 = int, _T1 = std::vector<int>, _T2 = int]' [enabled by default] scratch.cpp:6:55: warning: (you can disable this with -fno-deduce-init-list) [enabled by default] Looking at the implementation:
template<typename _T1, typename _T2> class tuple<_T1, _T2> : public _Tuple_impl<0, _T1, _T2> { typedef _Tuple_impl<0, _T1, _T2> _Inherited; public: //... template<typename _U1, typename _U2> explicit tuple(_U1&& __a1, _U2&& __a2) : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } //... } He seems to be complaining that he is sending from initializer_list<int> ( {1, 2, 3} in my code) to std::vector<int> , which will be the first type in std::tuple . It seems to me that everything is in order.
So my question is: what does this warning mean?
This is more of an assumption than a quote from the standard, but I think it makes sense.
The problem is that a list enclosed in braces can mean many things. It can be a list of initializers, but according to uniform initialization, there can also be any number of other things, such as aggregate initializers or just constructor arguments.
Consider the following situation:
struct Bar { Bar(int, int, int){} }; void foo(const std::vector<int> & v); void zoo(const Bar & v); I can name both foo({1,2,3}) and zoo({1,2,3}) . Since the argument type of both functions is known, there is no ambiguity. However, the foo argument is displayed as a list of initializers, and the zoo argument is a constructor call with uniform initialization.
In a tuple situation, the problem is that all the types involved are templates. The constructor argument type must be inferred; It is not known at the time of the function call. This true role is manifested only in the body of the function.
Since there are many ways to build a member of a collection, this conclusion may be ambiguous or simply incorrect, so the compiler warns you that it makes an assumption.
In fact, you can build the failure of this assumption very simply:
std::tuple<Bar, std::vector<int>> s{{1,2,3}, {1,2,3}}; This will not be able to create the first member of the tuple, because the list of commands is displayed incorrectly. The only “good” way of writing tuples is explicitly:
std::tuple<Bar, std::vector<int>> s{Bar{1,2,3}, std::vector<int>{1,2,3}}; GCC warns because listing initialization lists is an extension. I suggest that the warning here should be consistent, as it should be considered an implementation diagnostic.