I'm looking at the ternary operator and I never used it before but would liek to know how it works, I've been looking at documentation for it but it doesnt say what exactly ? does and : does, i've just seen example of its use, what does the question mark mean? can there be multiple of them? what about the colon? what exactly does that do in the statement? can there be multiple of that as well?
would I be able to translate this to a ternary expression?
1 2 3 4
if(m_magazineCapacity < 0 || fireAmount > m_magazineCapacity)
{
throw std::invalid_argument("Error, magazine capacity too low or fire amount greater than magazine capacity of weapon.");
}
If so i'm a little confused as to how exactly do it. As a side question, is there any way to store that thrown exception in a variable and call it like: throw negativeAmmoException?
No, you can't use the conditional (a.k.a., "ternary") operator there.
It's an expression, not a statement, so it evaluates to a value, which is usually assigned to a variable or passed to a function.
It's used in situations like this:
1 2 3 4 5 6 7 8 9
int a = (x > y) ? 42 : 24; // The parens around x > y are not necessary
// which is equivalent to this:
int a;
if (x > y)
a = 42;
else
a = 24;
Another example:
1 2 3 4 5 6 7 8 9 10 11
my_function(123, x > y ? 1 : 2);
// which is equivalent to:
int tmp;
if (x > y)
tmp = 1;
else
tmp = 2;
my_function(123, tmp);
Sometimes people misuse it as a statement replacing an if statement, like this:
1 2 3 4 5
(x > y) ? cout << "yes" : cout << "no";
// But that's just stupid. Although it's reasonable to do this:
cout << (x > y ? "yes" : "no"); // parens necessary here due to low precedence of ?:
As for storing the exception in a variable:
1 2 3 4 5 6 7
std::invalid_argument negativeAmmoException(
"Error, magazine capacity too low or fire amount greater than magazine capacity of weapon.");
if (m_magazineCapacity < 0 || fireAmount > m_magazineCapacity)
{
throw negativeAmmoException;
}
Using a throw expression as one of the operands of the conditional operator is useful in situations where the initialisation of an object that is expensive to construct is involved.
For example:
1 2 3 4 5 6
struct foo
{
explicit foo( std::string str ) : b( str.size() < 5 ? throw"bad arg" : str ) {}
bar b ; // bar is expensive to construct/destroy
};
In contrast, this would require the construction and destruction of a bar object if the argument is invalid:
1 2 3 4 5 6 7
struct foo
{
explicit foo( std::string str ) : b(str)
{ if( str.size() < 5 ) throw"bad arg" ; }
bar b ; // bar is expensive to construct/destroy
};
These are some of the permissible ways in which the conditional operator can be used:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include <iostream>
#include <stdexcept>
int main()
{
int x = 9, y = 6, z = 0 ;
( x>y ? ( std::cout << "yes" ) : ( std::cout << "no" ) ) << '\n' ; // yes
z = x>y ? 23 : throw std::invalid_argument("blah!") ; // int z = 23 ;
try { z = x<y ? 999 : throw std::invalid_argument("blah!") ; } // throws
catch( const std::exception& e ) { std::cout << e.what() << '\n' ; } // blah!
// if x>y, add 10 to x, else add 10 to y
( x>y ? x : y ) += 10 ; // x += 10 (x any y are lvalues of the same type)
std::cout << x << ' ' << y << ' ' << z << '\n' ; // 19 6 23
}