3

Consider following c++ code:

#include <bits/stdc++.h>

template <typename T> void print_type() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

class Base{
    int num;
public:
    Base() : num{0} {}

    friend std::ostream & operator << ( std::ostream& stream, Base & obiekt){
        stream<< "num: " << obiekt.num;
        return stream;
    }
};

int main(){
    Base a{};
    std::cout << a << std::endl;
    std::cout << "type of a: " << std::endl;
    print_type < decltype( a ) > (); 

    std::cout << "type of (a): " << std::endl;
    print_type < decltype( (a) ) > ();


    Base b();
    std::cout << b << std::endl;

    std::cout << "type of b: " << std::endl;
    print_type < decltype( b ) > (); 

    std::cout << "type of (b): " << std::endl;
    print_type < decltype( (b) ) > (); 


    return 0;
}

I compiled it with g++ 7.2.0, and got following output:

num: 0
type of a: 
void print_type() [with T = Base]
type of (a): 
void print_type() [with T = Base&]
1
type of b: 
void print_type() [with T = Base()]
type of (b): 
void print_type() [with T = Base (&)()]

My questions:

  • Why std::cout << b << std::endl; prints "1"?
  • What is a type like Base() or Base (&)()?
  • Why type of (a) is Base&, when a has type Base?

I am looking for answer and I can't find it. I know in this case I should use declarations like Base a; without any brackets, but i want to know about difference between Base a;, Base a{}; and Base a();. Why it copiles without any warnings or errors? Thanks for help.

Edgar Rokjān
  • 16,412
  • 4
  • 37
  • 63
nonamenick
  • 33
  • 6
  • 3
    I believe `b` is declared as function returning `Base`. The `cout` converts `b` to a `bool` - hence, the output of `1`. (Consider, that `a` is printed as `num: 0` in opposition to `b`.) (But, I'm not quite sure. I'm looking forward for other comments and the answer.) – Scheff's Cat Feb 03 '18 at 20:52
  • This might be surprising as there is no definition of function `b()`. On the other hand, it's never called. If you try to call it (and I'm on the right track) this should bring a _link_ (instead of compile) error... – Scheff's Cat Feb 03 '18 at 20:53
  • 1
    Adding to Scheff's explanations, this is an example of what Scott Meyers named "Most Vexing Parse". You would find even a wikipedia article about this. It looks like declaring a variable, but the compiler parses a function declaration. – Jorge Y. Feb 03 '18 at 20:56
  • My mate said that Microsoft VS studio not compiles it. `print_type < decltype( b() ) > (); ` prints type `Base` so Scheff might be right. But what about answer on third question (type `Base&`) – nonamenick Feb 03 '18 at 21:02
  • @Scheff I am wondering why gcc even compiles and links it as `b` seems to be ODR-used... Probably, I am too sleepy and overlook something obvious. – Edgar Rokjān Feb 03 '18 at 21:03
  • @EdgarRokjān Yepp. That's why "I'm not quite sure." ;-) On the other hand, it's `g++ 7.2.0` (in words version **seven**). May be, something very modern kicks in which is beyond my imagination... – Scheff's Cat Feb 03 '18 at 21:05
  • 1
    @nonamenick regarding your third question, my guess is that you are applying the operator parentheses and it is returning you a reference to the object a. Thats why you see the "&", to point that "reference" status – Jorge Y. Feb 03 '18 at 21:13
  • 1
    Your mate is right. Good reading reading on that here: [Why should I not #include ?](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h) – user4581301 Feb 03 '18 at 21:18
  • Thanks for answers. @user4581301 Heh, my mate didn't copy it brainlessly. He changed includes. I know i shouldn't use `` but when i am learning or debuging it is comfortable, but thanks for advice and article. @JorgeY. When i checked type of int in parentheses i got int reference as well. It should be `int&` ? – nonamenick Feb 03 '18 at 21:33
  • I would say so. And the link from en.cpp.reference that Edgar posted in his elaborated answer seems to confirm it. – Jorge Y. Feb 03 '18 at 21:42

1 Answers1

4

The main problem is that:

Base b();

doesn't do what you think. In fact, it is a declaration of a function which accepts zero arguments and returns an object of type Base.


Why std::cout << b << std::endl; prints "1"?

Because b is a pointer to a function. As a result, an overload:

basic_ostream& operator<<( bool value );

is used and 1 is printed as a pointer to a function is never null.

A more interesting question is why gcc even accepts the code and produces only a warning. There is no definition for function b, only its declaration, so I expected the code not to link.


What is a type like Base() or Base (&)()?

Base() is a pointer to a function accepts no arguments and return Base, Base (&)() is a reference to the same function.


Why type of (a) is Base&, when a has type Base?

Because decltype works so:

decltype(expression)

If the argument is an unparenthesized id-expression or an unparenthesized class member access expression, then decltype yields the type of the entity named by this expression. If there is no such entity, or if the argument names a set of overloaded functions, the program is ill-formed.

If the argument is any other expression of type T, and

a) if the value category of expression is xvalue, then decltype yields T&&;

b) if the value category of expression is lvalue, then decltype yields T&;

c) if the value category of expression is prvalue, then decltype yields T.

Edgar Rokjān
  • 16,412
  • 4
  • 37
  • 63