1
struct Node
{
    int value;
    Node* left;
    Node* right;
    Node(int i = 0) :value(i), left(nullptr), right(nullptr) {}
};

auto left = &Node::left;
auto right = &Node::right;

int main()
{
    Node* root = new Node(0);
    std::cout << typeid(left).name() << std::endl;
    std::cout << left << std::endl;
    std::cout << typeid(root->left).name() << std::endl;
    std::cout << root->left << std::endl;
}

First Question: What does "auto left = &Node::left" means ? The Class Node donot be initialized an object, how can use "Node::left" to assign left ?
Second Question: Why the output of printing "left" is 1 ?

phuclv
  • 37,963
  • 15
  • 156
  • 475
  • you can use `auto` to declare a variable where the initialization expression involves templates, pointers to functions, or pointers to members. In the above case you attempt to assign the address of the `left` member of the struct Node. I doubt it is even working. – Anand Sowmithiran Dec 18 '21 at 06:11
  • SO is not a place for this. It's already explained in every "modern" C++ book. Please read one: [The Definitive C++ Book Guide and List](https://stackoverflow.com/q/388242/995714) – phuclv Dec 18 '21 at 06:14
  • auto means : let the compiler deduce the actual type. Which can really help code to be more readable and maintainable (refactorable). std::vector v; auto it = v.begin() is more readable then std::vector::iterator it = v.begin(); – Pepijn Kramer Dec 18 '21 at 06:17

3 Answers3

3

auto allows the compiler to deduce the type of a variable declaration based of what type of value is used to initialize it.

In this case, auto left is deduced from &Node::left, and auto right is deduced from &Node::right, as both being a pointer-to-data-member of type Node* Node::* (ie, a pointer to a Node member which is of type Node*). Such pointers can be used with the .* and ->* member access operators.

The reason that 1 is output when printing such a pointer is because operator<< does not have an overload that takes such a pointer, but it does have one that takes a bool, and there is an implicit conversion defined from a pointer to a bool. By default, a bool is printed by operator<< as an integer 0 or 1. If you enable the boolalpha flag on the stream (such as with the std::boolalpha stream manipulator), the pointer will be printed as true instead of 1.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thank you. I have known the reason of second question. However, for the first question, the Node struct doesnot be instatiated, so the member left doesn't exist in the memory. How can use "&" to get its address ? – stupied-ies Dec 18 '21 at 14:56
  • `struct Node { int value; Node* left; Node* right; Node(int i = 0) :value(i), left(nullptr), right(nullptr) {} }nodes; auto left = &nodes.left; auto left2= &Node::left; ` So what is the difference between left and left2. If I print left, I will get a address. While if I print left2, I will just get true – stupied-ies Dec 18 '21 at 15:13
  • Thank you very much, sir. After reading the link of pointer-to-data-member, I've got it. – stupied-ies Dec 18 '21 at 15:47
0

auto is a C++ feature that arrived in the dawn of C++ 11.

It does mostly 2 things for you:

  1. Shorter syntax. Who doesn't like writing shorter types, right? Although sometimes it's not practical, and it's really up to the person to decide. So for example, this:
std::vector<unsigned int>::size_type i = 0;

...gets reduced to:

auto i = 0;

And that's what I was talking about, regarding practicality. Sometimes, there are lots of C++ types, tons of numbers, uint32_t, int, etc. Sometimes what the compiler deduces for you is not accurate. Or specific, for that matter.

  1. Get the type for you, as easy as 1-2-3 (or not). So what if we had a variable with a type that's ambiguous, say for example, we had this function:
void do_work(auto &ref);

...we don't know the type, yeah? You could use templates, but this is another way to do it, really. That gets the type for you, then tells you what it is when the function is called.


Adding auto to any variable or whatever that deals with data types basically tells the compiler: "hey you! Get the type of this variable based on it's initializer", so if the initializer was a vector, deque, or something else, C++ will use that.

Fun fact: "Auto", according to Oxford Languages, also stands for "one's own." (so maybe the compiler really makes decisions).

Good resource for reading!: https://github.com/AnthonyCalandra/modern-cpp-features/blob/master/CPP11.md#auto.

Justin
  • 183
  • 1
  • 1
  • 8
  • check this link additionally https://www.geeksforgeeks.org/type-inference-in-c-auto-and-decltype/ – Qwerty Dec 18 '21 at 06:56
0

You can use C++ Insights to get a better understanding what the compiler is doing:

// [...]

auto left = &Node::left;
auto right = &Node::right;

// [...]

becomes:

// [...]

using MemberVarPtr_11 = Node *Node::*;
MemberVarPtr_11 left = &Node::left;

using MemberVarPtr_12 = Node *Node::*;
MemberVarPtr_12 right = &Node::right;

// [...]

In other words, the variable left has type Node *Node::*. This is a pointer to a member of Node hat has type Node*.

This is not useful unless you are trying to be fancy or working on the internals of some framework or library. That syntax can be used for example to do reflection at runtime (making it possible to access a member by name):

// Magic, implemented by framework
#define REGISTER_PROPERTY(name, member_pointer)

struct A {
    A() {
        // You inform the framework about available members.
        REGISTER_PROPERTY("foo", &A::foo);
    }

    int foo;
};

In Godot you can add custom modules in C++ and the scripting language can then interact with it using some reflection mechanism. To make this work you need to declare all the accessible methods:

void Summator::_bind_methods() {
    ClassDB::bind_method(D_METHOD("add", "value"), &Summator::add);
    ClassDB::bind_method(D_METHOD("reset"), &Summator::reset);
    ClassDB::bind_method(D_METHOD("get_total"), &Summator::get_total);
}

That's using member function pointers but the same can be done with members.

asynts
  • 2,213
  • 2
  • 21
  • 35