Question

  Time &Time::setHour( int h ) 
  {
     hour = ( h >= 0 && h < 24 ) ? h : 0; 
     return *this; 
  } 


  Time &Time::setMinute( int m ) 
  {
     minute = ( m >= 0 && m < 60 ) ? m : 0; 
     return *this;  
  } 


  Time &Time::setSecond( int s ) 
  {
     second = ( s >= 0 && s < 60 ) ? s : 0; 
    return *this; 
   }

int main()
{
    Time t;     
    t.setHour( 18 ).setMinute( 30 ).setSecond( 22 );
    return 0;
}

I understand the cascaded member function call, but I don't understand how t.setHour( 18 ).setMinute( 30 ).setSecond( 22 ); is left hanging, doesn't it have to be assigned to something since it still returns *this after it's done cascading? Why is it ok to leave it like that?

Was it helpful?

Solution

The value of the expression which is used as a statement is discarded. It's the same thing that happens when you write

scanf("%d", &i);

You did know that scanf has a return value, right? And so does ++i in

for( int i = 0; i < 10; ++i )

And even

x = 5;

is throwing away the result of the expression.

There are lots of expressions and functions with return values that are only marginally useful. If you want to write the code in a way that makes it clear the return value is ignored intentionally and not by accident, cast to void:

(void) scanf("%d", &i);

This should silence compiler warnings about ignored return values.

These variations are also valid but a bit sillier:

(void)++i;
(void)(x = 5);

OTHER TIPS

This is called a "fluent syntax", "fluent interface", or "method chaining". You are utterly free to ignore/throw-away/don't bother with a return value if it is provided (but you're not interested in it). It makes chaining function calls together easier (and which boat you sit in on whether that is good or bad is entirely up to you).

Therefore, each method is returning *this to allow you to chain these calls together, but the last one is just dumped, ignored, not used.

This is perfectly fine.

Since someone asked for a standard citation in a comment...

This is called an "expression statement". The C++11 standard says this about it:

6.2 Expression statement [stmt.expr]

Expression statements have the form

expression-statement:
    expression (opt);

The expression is a discarded-value expression (Clause 5). All side effects from an expression statement are completed before the next statement is executed. An expression statement with the expression missing is called a null statement. [Note: Most statements are expression statements — usually assignments or function calls. A null statement is useful to carry a label just before the } of a compound statement and to supply a null body to an iteration statement such as a while statement (6.5.1). — end note]

Regarding the "discarded-value expression", Clause 5 says:

In some contexts, an expression only appears for its side effects. Such an expression is called a discarded-value expression. The expression is evaluated and its value is discarded. ...

It is just an expression statement, doing meaningful stuff via the side effects within the function calls.

You don't have to do anything with the value of an expression.

int f(int x) { return x * x; } 
int main(int argc, char* argv[]) { f(2); } 

is legal C++.

If you want to verify it, check a C++ grammar, e.g. http://homepages.e3.net.nz/~djm/cppgrammar.html

statement:
  labeled-statement
  expression-statement
  compound-statement
  selection-statement
  iteration-statement
  jump-statement
  declaration-statement
  try-block
// ..
expression-statement:
    expression;  // opt.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top