Language[lang]

C++ ternary operator (?:): syntax and examples

Section
Language [lang]
Standard
C++17
Compilers
MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2, Clang 23.1 (libc++)
Published
Length
7 min read
In this answer7 clauses
  1. 1Ternary operator vs if-else: what is the difference?
  2. 2When should you use the ternary operator?
  3. 3What type does the ternary operator return (numbers and strings)?
  4. 4Can you nest ternary operators?
  5. 5Why does cout << x ? a : b print the wrong thing?
  6. 6Does the ternary operator evaluate both sides?
  7. 7Ternary or if-else: which one?

Abstract

The C++ ternary operator, condition ? a : b, is an expression that gives a when the condition is true and b when it is false, so it can initialize a variable, a const one included, or sit in a return or a function argument. Both branches must agree on a type, only the chosen one is evaluated, and inside a std::cout chain it needs parentheses.

A line runs into a diamond and splits in two. The upper path passes a hatched block; the lower path and its block are grey. Both paths join again at one blue dot, and a single line leaves it.
Figure 1 — Two possible values, one result.

The C++ ternary operator, condition ? a : b, is an expression that gives a when the condition is true and b when it is false. It is a compact if-else that produces a value, so it can sit where a statement cannot: in an initializer, a return or a function argument. Its formal name is the conditional operator.

A test score, in a whole program:

[Example 1:
#include <iostream>
#include <string>

int main() {
    int score = 72;
    std::string result = score >= 60 ? "pass" : "fail";
    std::cout << "Score " << score << ": " << result << '\n';
}

— end example]

It printed:

[Example 2:
Score 72: pass

— end example]

Read the line as “if the score is at least 60, then pass, otherwise fail”. score >= 60 is the condition, anything that converts to bool; 72 meets it, so result holds “pass”. The operator needs no header and has been in C++ since C++98. The samples are C++17 (Since When’s C++17 table lists the first GCC, Clang and MSVC releases for its features), built with MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2 and Clang 23.1 (libc++), and all four printed the same.

Ternary operator vs if-else: what is the difference?

An if-else is a statement, a step the program carries out: it does one thing or another. The ternary operator is an expression, a piece of code that has a value: it is one value or another. The same choice, both ways:

[Example 3:
std::string by_if;
if (score >= 60) {
    by_if = "pass";
} else {
    by_if = "fail";
}

std::string by_ternary = score >= 60 ? "pass" : "fail";

std::cout << by_if << ' ' << by_ternary << '\n';  // pass pass

int age = 9;
const int fee = age < 12 ? 5 : 10;  // a const set in one step
std::cout << "Fee: " << fee << '\n';  // Fee: 5

— end example]

The if-else declares by_if empty and sets it in one of two places; the ternary sets by_ternary as it is declared. That matters for the entry fee: fee is const, a variable that cannot change once set, so an if-else could not assign it afterwards, while the ternary gives it its value in one step.

Question if-else Ternary operator
What it is a statement an expression
Gives a value no yes
Each branch holds any statements one expression
The code line result = score at least 60 ? “pass” : “fail”; set large. Brackets above it mark the condition, the value if true and the value if false; an arrow leads from the whole expression back to result.
Figure 2 — The ternary condition ? a : b is an expression: it becomes a when the condition is true, b when it is false.

When should you use the ternary operator?

Use it for a short choice between two values: to initialize a variable, in a return, as a function argument, or to pick a singular or plural word. Each of those is a place that needs a value:

[Example 4:
int larger(int a, int b) {
    return a > b ? a : b;
}

void announce(const char* result) {
    std::cout << "Result: " << result << '\n';
}

int main() {
    std::cout << larger(72, 85) << '\n';  // 85

    int score = 72;
    announce(score >= 60 ? "pass" : "fail");  // Result: pass

    int count = 1;
    std::cout << count << (count == 1 ? " item" : " items") << '\n';
    count = 3;
    std::cout << count << (count == 1 ? " item" : " items") << '\n';
}

— end example]

The last two lines printed 1 item and 3 items. Write an if-else instead when the two sides do different things rather than give different values, or when either side is long enough that the ? and the : get lost in it.

What type does the ternary operator return (numbers and strings)?

The whole expression has one type, worked out from both branches: an int and a double give a double, and a string literal (text in double quotes) with a std::string gives a std::string (the conditional operator on cppreference). Below, decltype names the type of an expression and std::is_same_v asks whether two types are the same:

[Example 5:
std::cout << std::boolalpha;

bool member = true;
auto price = member ? 8 : 9.5;  // int and double: double
std::cout << std::is_same_v<decltype(price), double> << '\n';
std::cout << price << '\n';  // 8, held as 8.0

bool ok = true;
std::string label = ok ? "yes" : std::string("no");
std::cout << label << '\n';  // yes

// the type of each whole expression, checked by the compiler
using Mixed = decltype(ok ? "yes" : std::string("no"));
using Words = decltype(ok ? "yes" : "no");
std::cout << std::is_same_v<Mixed, std::string> << '\n';
std::cout << std::is_same_v<Words, const char*> << '\n';

— end example]

Every check printed true. price is a double though member picked the 8, and std::cout printed it as 8. Two string literals, ok ? "yes" : "no", give a pointer to characters (const char*), not a std::string. With auto, the first example’s result would have been a const char*. To get a std::string from a choice between two pieces of text, declare the variable as std::string, as that example does, or make one branch a std::string, as label does.

Branches with no common type do not compile:

[Example 6:
auto value = ok ? 1 : "none";  // error: a number or text?

— end example]

GCC said:

[Example 7:
error: operands to '?:' have different types 'int' and 'const char*'

— end example]

All four refused it. One branch may instead be a throw, which has no value; the expression then takes the other branch’s type (how try, catch and throw work).

Can you nest ternary operators?

Yes. A nested ternary operator has another ternary as a branch, and laid out with one condition per line it reads as a chain. A letter grade from a score, beside the same chain as an if-else:

[Example 8:
char grade_ternary(int score) {
    return score >= 90 ? 'A'
         : score >= 80 ? 'B'
         : score >= 70 ? 'C'
         : score >= 60 ? 'D'
         : 'F';
}

char grade_if(int score) {
    if (score >= 90) {
        return 'A';
    } else if (score >= 80) {
        return 'B';
    } else if (score >= 70) {
        return 'C';
    } else if (score >= 60) {
        return 'D';
    } else {
        return 'F';
    }
}

— end example]

For 95, 72 and 41 both returned A, C and F. The operator groups from the right, so the chain is read as score >= 90 ? 'A' : (score >= 80 ? 'B' : ...) with no parentheses written: each line that starts with : is the else of the line above it. Past three outcomes, prefer the if-else chain: it is as easy to scan, and any branch can grow into more than a value.

Why does cout << x ? a : b print the wrong thing?

Because << binds tighter than ?:, std::cout << passed ? "pass" : "fail"; sends passed to the stream and throws the chosen word away. Put the ternary in parentheses:

[Example 9:
bool passed = true;

std::cout << passed ? "pass" : "fail";  // prints 1
std::cout << '\n';

std::cout << (passed ? "pass" : "fail") << '\n';  // prints pass

— end example]

It printed:

[Example 10:
1
pass

— end example]

The first line is read as (std::cout << passed) ? "pass" : "fail"; (the operator precedence table puts << far above ?:), so the bool is printed as 1, the stream itself (which converts to bool) becomes the condition, and the chosen word goes nowhere. Do not count on a warning: Clang says operator '?:' has lower precedence than '<<'; '<<' will be evaluated first even with no warning flags, GCC with -Wall only that the second and third operands, the two values, have no effect, and MSVC at /W4 says nothing.

With a comparison as the condition, the same slip does not compile:

[Example 11:
std::cout << score >= 60 ? "pass" : "fail";  // error

— end example]

<< runs first again, so >= is asked to compare the stream with 60. GCC said no match for 'operator>=', and all four refused it. The same parentheses fix it, and they are why the item lines earlier wrap their choice in them. An assignment needs none: a = b ? c : d is read as a = (b ? c : d).

Does the ternary operator evaluate both sides?

No. Only the chosen branch runs ([expr.cond]: “only one of the second and third expressions is evaluated”), which is what makes count != 0 ? total / count : 0 safe:

[Example 12:
int pass_bonus() {
    std::cout << "pass_bonus called\n";
    return 5;
}

int fail_bonus() {
    std::cout << "fail_bonus called\n";
    return 0;
}
// ...
int score = 72;
int bonus = score >= 60 ? pass_bonus() : fail_bonus();
std::cout << "bonus " << bonus << '\n';

int total = 0;
int count = 0;
int average = count != 0 ? total / count : 0;  // no division
std::cout << "average " << average << '\n';

— end example]

It printed pass_bonus called, bonus 5 and average 0: fail_bonus never ran, and with count at 0 the division was never evaluated.

Ternary or if-else: which one?

Pick by what the code has to produce:

You need Write
One value from a yes-or-no question a ternary
A const set from a condition a ternary
Two different actions an if-else
More than three outcomes an if-else chain or a switch
A choice inside a std::cout << chain a ternary in parentheses

C++ does not let you overload ?:; how to overload operators in C++ covers the ones you can. The Language section has the other answers on the core language.

Questions

What is the ternary operator called in C++?

Its formal name is the conditional operator. “Ternary” means it takes three operands, the values an operator works on: the condition and the two branches. It is the only C++ operator that always takes exactly three.

Can a ternary operator have multiple statements?

No. Each branch is a single expression, not a block, so it cannot hold statements such as a declaration, a loop or a return. To return one of two values, put the ternary after the return, as in return a > b ? a : b;. When a branch has to do several things, write an if-else.

Can a ternary operator have multiple conditions?

Yes. The condition is any expression that converts to bool, so it can join tests with && and ||, as in const int fee = age < 12 || age >= 65 ? 5 : 10;, which gave 5 for an age of 70. Both operators bind tighter than ?:, so the condition needs no parentheses.

Can you use a ternary operator without else?

No. The grammar requires both branches, the one after the ? and the one after the :, so there is no form without the second. To do something only when a condition holds, write an if with no else.

Can you assign to the result of a ternary operator?

Yes, when both branches are variables of the same type: the result is then one of the two variables, not a copy of its value. With a = 72 and b = 45, (a < b ? a : b) = 0; set b to 0, and the program printed 72 0.

Can you throw inside a ternary operator?

Yes. One branch may be a throw expression, as in int age = text_ok ? 30 : throw std::runtime_error(“bad age”), and the whole expression then has the type of the other branch, here int. When text_ok is false, the exception is thrown and no value is produced; a handler such as catch (const std::runtime_error& e) receives it.

Sources

  1. Other operators: the conditional operatorcppreference.com
  2. C++ operator precedencecppreference.com
  3. [expr.cond] Conditional operatorC++ standard working draft

Read next

  1. const in C++: variables, pointers, references, methodsLanguage · Miriam Castellanos · written for C++17
  2. using namespace std: what it does and what to write insteadLanguage · Miriam Castellanos · written for C++17
  3. C++ operator overloading: signatures, member or friendLanguage · Miriam Castellanos · written for C++20