some function call does not require parentheses?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//Fig. 13.9: Fig13_09.cpp
//Creating and testing user-defined, nonparameterized
//stream manipulator

#include <iostream>

using namespace std;

//bell manipulator (using escape sequence \a)
ostream& bell(ostream& output)
{
    return output << '\a'; //issue system beep
}

//carriageReturn manipulator (using escape sequence \r)
ostream& carriageReturn(ostream& output)
{
    return output << '\r'; //issue carriage return
}

//tab manipulator (using escape sequence \t)
ostream& tab(ostream& output)
{
    return output << '\t';
}

//endLine manipulator (using escape sequence \n and flush stream
//manipulator to simulate endl)
ostream& endLine(ostream& output)
{
    return output << '\n' << flush; //issue endl like end of line
}

int a = 20;
int getB()
{
    return a;
}


int main()
{
   cout << "Testing the tab manipulator:" << endLine
        << 'a' << tab << 'b' << tab << 'c' << endLine;

    cout << "Testing the carriageReturn and bell manipulators:" << endLine << "..........";

    cout << bell;

    //use carriageReturn and endLine manipulators
    cout << carriageReturn << "-----" << endLine;
}
>


1) why carriageReturn, endLine and bell does not require any parentheses?

2) how does the ostream reference get passed as argument to the function since it is not a operator overloaded function?
Last edited on
std::ostream::operator<< is overloaded for arguments with type
std::ostream&(*)(std::ostream&)

It calls the pointed-to function with itself as an argument. For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <cstdio>
struct my_ostream 
{ 
  my_ostream & operator<<(my_ostream&(*pf)(my_ostream&)) { return pf(*this); } 
};

my_ostream& foo(my_ostream& s) { std::puts("hello"); return s; }; 

int main()
{
  my_ostream x; 
  x << foo; // calls foo; prints hello
}
Last edited on
To clarify, cout << bell is not a function call to bell(), it's a function call to an operator<<() overload that passes [a function pointer to bell()] to the overload. Inside the overload, the function pointer is called.
> 1) why carriageReturn, endLine and bell does not require any parentheses?

carriageReturn, endLine and bell are function of type std::ostream&(std::ostream&)

There is an implicit conversion from function to pointer to function.
https://en.cppreference.com/w/cpp/language/implicit_conversion#Function_to_pointer


> 2) how does the ostream reference get passed as argument to the function since it is not a operator overloaded function?

There is an overloaded operator.
11-13) Calls func(*this). These overloads are used to implement output I/O manipulators such as std::endl.
https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

std::ostream& test_it( std::ostream& stm )
{
    return stm << "test it\n" << std::flush ;
}

int main()
{
    using function_type = std::ostream&( std::ostream& ) ;
    function_type* ptr_to_fn = test_it ; // implicit conversion from function to pointer to function

    std::cout << test_it ; // implicit conversion from function to pointer to function
    std::cout << ptr_to_fn ;
    std::cout.operator<< ( test_it ) ; // calls test_it(std::cout)
    std::cout.operator<< ( ptr_to_fn ) ; // calls test_it(std::cout)
}
Do you guys mean there is an operator overloaded function that takes in an ostream& object?
which is something like


ostream& operator<<(ostream& output)
{
return output;
}
The https://en.cppreference.com/w/cpp/header/ostream lists:
1
2
3
4
using ostream  = basic_ostream<char>;

basic_ostream<CharT, Traits>&
operator<<( basic_ostream<CharT, Traits>& (*pf)(basic_ostream<CharT, Traits>&) );

Basically:
1
2
ostream&
operator<<( ostream& (*pf)(ostream&) );

This ostream member function that does take a pointer to function as argument.
The type of the pointer argument is ostream& (*)(ostream&)

Since this overload of << is a member, it has this pointing to the ostream.
As shown in mbozzi's example, the implementation of that member function could look like:
1
2
3
4
5
ostream&
ostream::operator<<( ostream& (*pf)(ostream&) )
{
  return pf( *this );
}


[edit] Lets emphasize:
1
2
3
4
5
6
7
8
using T = ostream;
using U = ostream;

T&
U::operator<<( T& (*pf)(U&) )
{
  return pf( *this );
}

Last edited on
if you want to circle back to the big question, there are several other ways to "call a function without ()".
you can write a macro that hides the () as the most derpy one. This is just hiding the syntax.
constructors are another example. type foo; //ctor is invoked, which can do whatever it wants!
any operator overload. eg !foo can do whatever it wants inside too.
on the flipside, you can call operators with ():
foo.operator !(); //something like this. I may not have the exact syntax, its not something you need to do often.

there are probably some other ways as well, but those are the more common ones. Its best if you do not go out of your way to do this as it makes code harder to read. Many languages do not allow operator overloading because you can do such unreadable, convoluted nonsense with it (like having your assignment operator draw on the screen, eg to draw a triangle you say x =1 or to draw a square say x = 2; ... you can't follow code written like that esp if it has no comments...)

Topic archived. No new replies allowed.