Every self-respecting C/C++ programmer knows what the ternary operator is, and most everyone used it at least once in their programs. But do you know all the secrets of the ternary operator? What potential dangers are associated with its use and what features, seemingly not related to its direct purpose, it has? This article gives you the opportunity to test your knowledge and maybe learn something new.

## Test

Will the following code compile? Explain why.

1.

``````int i;
int j;
(false ? i: j) = 45;``````

2.

``````int i;
int j;
(true ? i: j) = 45;``````

3.

``````short i;
int j;
(true ? i: j) = 45;``````

4.

``return true ? 0 : 1;``

5.

``true ? return 0 : return 1;``

6. What will be the output of the following piece of code? Why?

``std::cout << (false ? 9 : '9') << " " << (true ? 9 : '9');``

7. What values will have variables a, b and c as a result of the following code execution? Why?

``````int a = 1;
int b = 1;
int c = 1;
a = true ? ++b : ++c;``````

8. Name a situation, in which you cannot useif{...} else{...}, but can use the ternary operator.

9. What are the potential dangers hiding in the use of the ternary operator What is the cause?

10. What unexpected use of the ternary operator comes to your mind?

## Explanation

So, let’s start. The ternary operator stands out from other operators in C++. It is called the "conditional expression". Since it’s an expression, it should also have the type and value category, just like any other expression. Actually, if we answer the questions about the type and the value category of the ternary operator in each of the first seven questions of the test, it will be pretty easy to solve them.

Here comes the fun part. It turns out that the type of the ternary operator is the most common type of his last two operands. What does the most common mean? The easiest way to explain this is to use examples. The common type of int and short is int.

The common type of A and B in the next fragment of code is also int.

``````struct A{ operator int(){ return 1; } };
struct B{ operator int(){ return 3; } };``````

Thus, the most common type is the type, which both operands can be converted to. There can be situations when there’s no common type. For example,

``````struct C{};
struct D{};``````

have no common type, and the following code will not compile:

``(true ? C() : D());``

I guess the type of the ternary operator is clear now. Now, let’s talk about the value category. The following rule applies here: if types in the ternary operator are converted to the most common one, the ternary operator is rvalue. If not, it is lvalue. Knowing this, we can easily answer the first 7 questions.

1. and 2. — Yes, it will. Types are not converted, and it’s quite possible to assign a value to lvalue.

3. — No, it won’t compile. The conversion of types takes place here, which means that the value category of the expression on the left from "=" is rvalue. As you know, rvalue can not be assigned.

4. — Yes, it will. All of us have done so more than once.

5. — No, it won’t. The thing is that a statement cannot break an expression in С++.

6. The program will print “57 9”. Since the 2nd and the 3rd operands are of different types, the conversion to the most common type takes place here. In the given case, it is int. And, as we know, '9' has ASCII code 57.

7. Another feature of the ternary operator is hiding in this question. Namely, out of the second and the third operands, the only one is being computed — the operand reached by the execution thread.

However, the same behavior can be observed in if {...} else {...}. Thus, the values of variables a, b and с will be 2, 2, 1.

### In what situations we can't use if {...} else {...}, but can use the ternary operator?

For instance, when initializing constructor. We cannot write the following:

``````struct S
{
S() : if(true) i_(1) else i_(0){}
int i_;
};``````

But we can do it like this:

``````struct S
{
S() : i_(some_condition ? 0 : 1){}
int i_;
};``````

That is to say, during the initialization of a reference depending on the condition. As we know, we cannot declare an uninitialized reference. Therefore, the following code fragment will not compile:

``````int a = 3;
int b = 4;
int& i;
if(some_condition)
i = a;
else
i = b;``````

While this fragment will compile successfully:

``int& i = (some_condition ? a : b);``

In C++11, the ternary operator is applied much more often. That's because the constexpr functions should have nothing but the return `expression`. While the `expression` may well be a ternary operator.

As an example, I’ll provide a classic algorithm for determining the primality of a number.

``````constexpr bool check_if_prime_impl(unsigned int num, unsigned int d)
{
return (d * d > num) ? true :
(num % d == 0) ? false :
check_if_prime_impl(num, d + 1);
}
constexpr bool check_if_prime(unsigned int num)
{
return (num <= 1) ? false :
check_if_prime_impl(num, 2);
}``````

By the way, the same example shows the use of nested ternary operators, where multiple ternary evaluations are also possible, so that to avoid multiple if {...} else {...} (don't drink too much kool-aid — for the sake of readability, if {…} else {…} might be a better choice).

### Dangers of the Ternary Operator

Suppose we have a String class

``````class String
{
public:
operator const char*();
};``````

and we can use it like this:

``const char* s = some_condition ? "abcd" : String("dcba");``

As we already know, the second and third operands of the ternary operator are converted to the most common type. In this case, it is const char*. But the String(«dcba») object will be destroyed at the end of the expression, and s will point to the invalid memory. In the best case, the program will crash trying to use s later. In the worst case, it will produce wrong results, causing dissatisfaction among customers and a headache for the programmer.

### An “Unusual” Use of the Ternary Operator

We can use the ternary operator to determine the common type of two and more types. This can also be used to determine whether one type is converted to the other one.

``````template
struct common_type
{
typedef decltype(true ? std::declval() : std::declval()) type;
};
template
struct is_same{ enum { value = false; } };
template
struct is_same{ enum { value = true; } };
int main()
{
std::cout << is_same::type>::value <``````
``` In fact, if you know the features of the ternary operator, such usage almost suggests itself. The unusual thing here is perhaps that it is not used for the intended purpose, i.e. not for selecting one value out of two, depending on the condition. ```
``` START WRITING AT KUKURUKU HUB (adsbygoogle=window.adsbygoogle||[]).push({}); google_ad_client="ca-pub-5957750206575747";google_ad_slot="4872645719";google_ad_width=300;google_ad_height=250; #c++ #ternary opeartor #conditional operator 13071 2 Y Published by Kukuruku Hub RATING: 15.51 Published in C++C++ is a high-level programming language developed by Bjarne Stroustrup. But you know that, right? 0  Written by Alex Kulikov 2 Y ```
``` RECOMMENDED Algorithms Exact Maximum Clique for Large or Massive Real Graphs Algorithms Julia Set C++ Lock-Free Data Structures. Yet Another Treatise Game Development How I built my first Android Game and realized creativity is all about iterations DIY USB Killer Programming I Do Not Know C Subscribe to Kukuruku Hub Or subscribe with RSS 2 comments Mironov Andrey 8 March 2015, 7:31 AM ↓    The following rule applies here: if types in the ternary operator are converted to the most common one, the ternary operator is rvalue. Imagine a situation where both types can be converted to some common lvalue reference type. I speak types with user-defined conversion operators. Gabriel 19 February 2016, 5:47 AM ↓    struct A { operator int() { return 1; } }; struct B { operator int() { return 3; } }; int main() { A a; B b; true? a: b; } Visual C++ 2015 refuses to compile the previous snippet and the error is: no conversion from 'B' to 'A' Both gcc and clang compile successfully and the result is as expected. Which in wrong? Visual C++ or gcc+clang? Upload image From PC From internet File Align No Left Right Center Title Image URL Align No Left Right Center Title or pagespeed.lazyLoadImages.overrideAttributeFunctions(); var markitupEditor={lang:{"panel_b":"bold","panel_i":"italic","panel_u":"underline","panel_s":"strike through","panel_url":"type link","panel_url_promt":"Type link","panel_code":"code","panel_video":"video","panel_image":"image","panel_cut":"cut","panel_quote":"quote","panel_list":"List","panel_list_ul":"UL LI","panel_list_ol":"OL LI","panel_title":"Header","panel_clear_tags":"clean up the tags","panel_video_promt":"Enter a link to the video","panel_list_li":"list item","panel_image_promt":"Enter the link to an image","panel_user":"user inserted","panel_user_promt":"Enter the user login"}}; Read Next Exact Maximum Clique for Large or Massive Real Graphs 17089 Algorithms AVL Trees 47945 C++ Comparing Rust and C++ 53977 Rust Hi Everyone! We are about to launch a new project very soon - CrowdMind.co. Sign up to get a private beta access! About Rules Privacy Policy · Twitter Facebook Log In Remember me Forgot password? ﻿ or Sign in with Github Sign in with Twitter We'll never post to your Twitter, Facebook or Github account without your permission. pagespeed.lazyLoadImages.overrideAttributeFunctions(); var socialAuth={facebook:{client_id:"1446177405629271",redirect_uri:'https://kukuruku.co/login/'+'openid/fb/',scope:"user_birthday,user_website,email,user_about_me"},twitter:{redirect_uri:'https://kukuruku.co/login/'+'openid/twitter/?authorize=1'}}; Don't have an account? Sign up now Sign Up ﻿ or Sign in with Github Sign in with Twitter We'll never post to your Twitter, Facebook or Github account without your permission. pagespeed.lazyLoadImages.overrideAttributeFunctions(); var socialAuth={facebook:{client_id:"1446177405629271",redirect_uri:'https://kukuruku.co/login/'+'openid/fb/',scope:"user_birthday,user_website,email,user_about_me"},twitter:{redirect_uri:'https://kukuruku.co/login/'+'openid/twitter/?authorize=1'}}; Already have an account? Log in here Reset Password Enter the email address associated with your account, and we'll email you a link to reset your password. Already have an account? Log in here ls.lang.load({"blog_join":"Connect","blog_leave":"Disconnect"});ls.registry.set('comment_max_tree',7);ls.registry.set('block_stream_show_tip',true); ```