0

I'm learning to use C++11 stuff, and ran into a situation where I'm not sure how to use auto. Consider:

struct MyClass { double x; }
std::vector<MyClass*> myvec;
function_that_fills_vector(myvec);

//(1) this should be valid:
for(auto* item : myvec){ std::cout<< item->x <<std::endl; }

//(2) what about this?
for(auto item : myvec){ std::cout<< item.x <<std::endl; }
//(3) or this?
for(auto item : myvec){ std::cout<< item->x <<std::endl; }

That is, if I know my auto is really a pointer, I can be explicit about it in the constructor, so I know the dereference operator is the right one. But if I change myvec to hold objects, (1) will not compile anymore.

In (2) and (3) the underlying pointer nature is left implicit. Which member access operator (. or ->) is correct? If both work, is there a good reason to use one or the other? Will both continue to work if I change myvec to be a vector<MyClass>?

bolov
  • 72,283
  • 15
  • 145
  • 224
thegreatemu
  • 495
  • 2
  • 11

4 Answers4

4

auto does not change the type or usage of the type.

Usually only one compiles. Use that.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
3

You should use the compiler to figure this out!

Here's a complete file:

#include <iostream>
#include <vector>

struct MyClass {
  double x;
};

int main() {
  struct MyClass m;
  std::vector<MyClass*> myvec;
  myvec.push_back(&m);

  for(auto* item : myvec){ std::cout<< item->x <<std::endl; }
  for(auto item : myvec){ std::cout<< item.x <<std::endl; }
  for(auto item : myvec){ std::cout<< item->x <<std::endl; }
}

Then we can look at the compiler output:

$ g++ fun.cc

fun.cc: In function ‘int main()’:

fun.cc:14:44: error: request for member ‘x’ in ‘item’, which is of pointer type ‘MyClass*’ (maybe you meant to use ‘->’ ?)

for(auto item : myvec){ std::cout<< item.x <<std::endl; }

If you remove line 14 (the second example) everything will compile. In other words:

In the first example auto refers to MyClass.

In the second it has to refer to MyClass* but then you can't access its members with '.'.

In the third it refers to MyClass*.

James Pinkerton
  • 161
  • 2
  • 14
  • I think that means that none of the suggested options works for both cases (vector of objects and vector of pointers). Somewhat surprising to me. – thegreatemu Apr 02 '18 at 23:43
  • It just depends on whether the compiler deduces the type to be a pointer or not. It uses template argument deduction rules, which work the same way. Compare: https://ideone.com/Uiuu5o – Daniel Waechter Apr 03 '18 at 00:22
0

These are two identical lines. The type of variable will be MyClass*

 //(1) this should be valid:
  for(auto* item : myvec){ std::cout<< item->x <<std::endl; }

  //(3) or this?
  for(auto item : myvec){ std::cout<< item->x <<std::endl; }

But this line should be not compiled. Because the type of variable will be MyClass* and you try to access to the members by operator.

  //(2) what about this?
  for(auto item : myvec){ std::cout<< item.x <<std::endl; }
VitkorAl
  • 44
  • 5
0

The type will be determined based on what type can be deduced by the compiler. From https://en.cppreference.com/w/cpp/language/auto

For variables, specifies that the type of the variable that is being declared will be automatically deduced from its initializer.

So basically, it will try the types it can deduce and if it finds one that matches it will use that.

Maybe if you are asking what type the auto is deducing to, then you possibly care enough to specify the type. But it does make sense that you can't use '.' for the pointer variable type, there is no type it can deduce to that will allow that.

Given no matter what the person reading this code will see you are using -> notation and can assume you have a pointer type, or a -> operator overload. So if you want to be explicit that it's definitely a pointer then go ahead. It only really aids in readability at the end of the day, both are just as easy to write.