Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicitly initializing vector of pointers results in conversion error?

Tags:

c++

visual-c++

Consider this:

std::vector<int*> v(1, 0);

This compiles fine with VC++10 (no warnings even at max warning level). However, it doesn't compile with llvm on mac or gcc on linux, giving an error like "assigning to int* from incompatible type const int." I'm not looking for solutions -- I know the second parameter is unnecessary or that a static_cast fixes the error.

I thought zero was implicitly convertible to any pointer type. What gives? I can do the following:

int* i = 0;
int* const& ii = 0;
const int t = 0;
i = t;

I understand that the vector constructor signature takes a const T& which when expanded for vector<int*> becomes int* const& correct? Can someone explain what is going on here, and whether the VC++ or non-VC++ compiler is correct?

like image 709
Tabber33 Avatar asked Apr 04 '12 19:04

Tabber33


2 Answers

It looks like g++ actually wrong here. See C++98 23.1.1/9:

For every sequence defined in this clause and in clause 21:

— the constructor template X(InputIterator f, InputIterator l, const Allocator& a = Allocator())

shall have the same effect as: X(static_cast<typename X::size_type>(f), static_cast<typename X::value_type>(l), a) if InputIterator is an integral type.

Note that InputIterator is a template parameter to the constructor, which in this case will be int for your example, and thus an integral type. The g++ library actually has specific code to handle all the cases where the type being stored in the vector is integral as well and those will all work properly. In this case, only because you used 0 would the static_cast dictated by the standard actually be legal. I tried compiling the code that the standard says should be equivalent and it compiles with g++ 4.5.

like image 123
Mark B Avatar answered Nov 09 '22 20:11

Mark B


std::vector has a nasty constructor with this signature

template <class InputIterator>
vector(InputIterator first, InputIterator last,
       const Allocator& = Allocator());

which, if the compiler deducts InputIterator as int(!) from your parameters 0 and 1, will be a good fit but not do what we want.

I believe C++11 requires the compiler to try harder to figure out if the parameters could actually be iterators or not. In C++03 they would probably end up as size_type(1) and int(0), causing your problem.

The integer literal 0 is convertible to a null pointer, but an int with value 0 is not!

like image 43
Bo Persson Avatar answered Nov 09 '22 22:11

Bo Persson