0

Consider the following code:

float validateEntry()
{
    string entry;
    float value;

    getline(cin, entry);
    value = atof(entry.data());

    return ((isNumber(entry) && value >= 0) ? i
    : (cout << "Enter valid amount: ", validateEntry())
}

Why is the last line (the comma-separated expression) allowed, and are there other expressions that can be used with return statements in C++?

I'm mostly confused at the use of the comma, and wondering where this expression syntax is defined (I had no idea it existed, nor would I have known where to find out). Can I fill that last expression with an indefinite amount of code; if so, what are the limitations, requirements, etc.?

skippr
  • 2,656
  • 3
  • 24
  • 39
  • 2
    Why do you think it should not be allowed ? – J.N. Mar 15 '12 at 00:43
  • By the way the ternary operator `? :` is not a shorthand for `if`. `if` allows conditionally executing code (any code). The ternary operator **returns** one value between two according to a condition. – J.N. Mar 15 '12 at 00:45
  • Sorry, a completely incorrect title, as I forgot to change it before posting. – skippr Mar 15 '12 at 00:47
  • 2
    @J.N.: If we're going to be pedantic, the ternary operator doesn't **return** anything. It *evaluates* to a *result*. – Josh Mar 15 '12 at 00:52
  • @user349433 : thanks for the precision. sunday: you should till tell us what's bothering you with that code. It will be hard to give any answers though. – J.N. Mar 15 '12 at 00:55
  • IIRC `std::string::data()` does not null-terminate, which is going to cause you problems if you pass its result to `atof`. – Lightness Races in Orbit Mar 15 '12 at 00:58
  • `return` or no `return`, what you've got there is all a valid C++ expression. – ephemient Mar 15 '12 at 00:59
  • @ephemient without a return, the function (which is intended to return a float) is pretty useless though, wouldn't you say? – skippr Mar 15 '12 at 01:03
  • Invalid, even. What I meant was that the expression following the `return` is valid irrespective of the fact that it's part of a `return` statement. – ephemient Mar 15 '12 at 01:04
  • @LightnessRacesinOrbit interestingly, the program runs fine with no errors. (?) atof will also return 0.0 if no conversion could be made. But maybe `c_str` should be used instead? Thoughts? – skippr Mar 15 '12 at 01:06
  • @Sunday: Invoking undefined behaviour is not required to cause an error any more than is it required _not_ to cause a black hole to open up inside your carefully-prepared evening meal. `c_str` is _definitely_ what you meant. – Lightness Races in Orbit Mar 15 '12 at 01:09
  • @Lightness FWIW, it didn't before, but it provides a null-terminated string in C++11. – R. Martinho Fernandes Mar 15 '12 at 01:09
  • @R.MartinhoFernandes Well, pre-11 didn't have `data`, anyway. – Christian Rau Mar 15 '12 at 01:12
  • @ChristianRau: Huh? Sure it did (`[C++03: 23.3.6/3]`) – Lightness Races in Orbit Mar 15 '12 at 01:12
  • @LightnessRacesinOrbit `data` behaves exactly like `c_str`. Both return a NUL-terminated string by standard. – Christian Rau Mar 15 '12 at 01:13
  • @ChristianRau: Only as of C++11, as we all just discussed already. In C++98 and C++03, `std::string::data` and `std::string::c_str` had differing semantics. – Lightness Races in Orbit Mar 15 '12 at 01:14
  • @LightnessRacesinOrbit I just looked it up and it seems you're right, there was indeed a `data` in pre-11 (and it doesn't behave like `c_str`). I had never ever heard of this method or seen it used before C++11. Sorry for that. – Christian Rau Mar 15 '12 at 01:17
  • @ChristianRau: Apology accepted :) You didn't need to look too hard, though; I cited chapter and verse for you! – Lightness Races in Orbit Mar 15 '12 at 01:18
  • Also, why would they introduce `std::string:data` in C++11, just to have the same semantics as a function in the same class that already exists? :P – Lightness Races in Orbit Mar 15 '12 at 01:22

4 Answers4

1
return [expression];

expression :
   expression , expression
   literal
   etc...

The comma operator separates multiple expressions on a single line. When used in an assignment statement like the return statement (assigning a temporary value which is returned), only the rightmost value is assigned. The preceding expressions are executed from left to right. In your example, the final function call returned value is returned.

I use this technique to clear formal argument variables on failure. Especially COM routines where there is a failure. For example:

HRESULT func(..., IInterface **ppv)
{
...
If(!good)
  return (*ppv = 0), E_FAIL;
...
}
Flexo
  • 87,323
  • 22
  • 191
  • 272
Mikey
  • 11
  • 1
1

The comma operator allows you to group two otherwise-unrelated expressions. Both expressions are always evaluated, and the result is the result of the second expression. It is almost always a bad idea to use it (because it hurts readability just to save a line of code), except maybe in the top of a for-loop.

Josh
  • 992
  • 5
  • 5
  • Ah, the COMMA OPERATOR. It all makes sense now. I didn't quite know where my question was going at first, because I didn't know the operator existed. This led me to: http://stackoverflow.com/questions/54142/c-comma-operator – skippr Mar 15 '12 at 01:12
0

, is an operator just like + or << so you can use it freely almost wherever an expression is expected. Exceptions are contexts where a comma is expected with a different meaning, such as in a function call. In such contexts you have to disambiguate the comma by adding an extra set of parens:

foo((b,c)); // call foo with a single argument

The statement you show is the equivalent of:

// return ((isNumber(entry) && value >= 0) ? i : (cout << "Enter valid amount: ", validateEntry())

if(isNumber(entry) && value >= 0) {
    return i;
} else {
    cout << "Enter valid amount: ";
    return validateEntry();
}

It's just a 'clever' way of conditionally executing the cout << "Enter valid amount: " before calling validateEntry() while using as few lines as possible. Of course the whole function is just a 'clever' way to repeatedly ask for an input until it gets valid input. IMO a loop would be better than recursion here.

bames53
  • 86,085
  • 15
  • 179
  • 244
0

? : is the only ternary opeartor of C++

its syntax is logical-or-expression ? expression : conditional-expression

You can read more about it at MSDN

Rohit Vipin Mathews
  • 11,629
  • 15
  • 57
  • 112