Understanding Type Predicates in C++
A standard-library type predicate is a simple type function that answers a fundamental question about types.
A Question Asked About a Type
Programs constantly deal with types, and sometimes the most useful thing a program can do is ask a plain question about one. Is this a type that behaves a certain way? Does this type have a property I need? Answering such questions by hand for every situation would be tedious and error-prone. The C++ standard library provides tools designed for exactly this purpose, and the first idea you need in order to use them is the type predicate.
What do you think happens?
Given the standard library predicate std::is_integral, what do you expect std::is_integral<int>::value to be: true or false?
Reveal answer
true
The type int is an integral type, so the predicate answers yes. Keep this answer in mind as you read the rest of the article, because the rest of the article explains why the answer is true and what that answer can be used for.
Before reading further, pause and think about what kind of answer a question about a type should produce. A question that can be answered only with yes or no is a particularly convenient kind of question, because the answer can be used directly to decide what a program does next. That idea is the key to everything that follows.
Following a Type Through a Predicate
A type predicate takes a type as its input and produces one answer, which is either true or false. Nothing about a particular value comes into play. You can picture the type going in on one side and a single yes-or-no result coming out on the other side. The diagram below traces the int type through the std::is_integral predicate.
Notice what is absent from this picture. There is no variable, no assignment, and no value being computed. The predicate looks only at the type it was given and reports a fact about that type. The word type function in the source description signals this: the predicate operates on types rather than on ordinary values.
Why the Word Predicate Fits
A standard-library type predicate is a simple type function that answers a fundamental question about types. The word predicate means the function returns a true-or-false answer about the type it is given.
Each part of that definition carries meaning. The word predicate comes from logic, where a predicate is a statement that is either true or false for a given subject. A type predicate follows the same pattern: it takes a type as its subject and returns a true-or-false answer about that type. The phrase fundamental question tells you that these predicates address basic questions, the kind a program is likely to need before it can make sound decisions about types.
A type predicate is not a special keyword and not a language rule that changes how types work. It is an ordinary function, supplied by the library, whose purpose is to answer a single fundamental question. Seeing it this way keeps the idea grounded in familiar territory: a function receives something, and it returns a result. Here the thing received is a type and the result is true or false.
Predicates Come From the Standard Library
The defining word in the description is standard-library. Type predicates are ready-made tools that come with the language's standard facilities. You do not need to invent the questions or write the logic that answers them from scratch. Your job is to know that a tool exists, understand which question it asks, and read its answer correctly.
In C++ the standard type predicates are provided through the type_traits header of the standard library. The program you write only includes that header and asks the predicate its question. The question-answering logic already lives inside the library. The learner's responsibility is choosing the right predicate and interpreting its answer.
Reading a Predicate as a Yes-or-No Question
The most reliable way to work with a type predicate is to translate it into a sentence. Each predicate asks one question, and its result is the answer. The expression std::is_integral<int>::value can be read as: is int an integral type? The answer is true. The expression std::is_integral<double>::value can be read as: is double an integral type? The answer is false.
1
0- The
type_traitsheader supplies the predicate; the program does not define the check itself. - The first line asks whether int is integral; the printed 1 means true.
- The second line asks whether double is integral; the printed 0 means false.
- Only types appear inside the angle brackets. No variable holding a value is involved.
Interpreting a predicate answer
A program needs to know whether a type T can hold whole-number values before it proceeds. It uses the predicate std::is_integral<T>::value. Walk through how to read the answer when T is int, and then when T is double.
- 1Identify the question
The predicate asks: is T an integral type? It is a yes-or-no question about the type T.
- 2Substitute the first type
With T set to int, the question becomes: is int an integral type? Yes, so the answer is true.
- 3Substitute the second type
With T set to double, the question becomes: is double an integral type? No, so the answer is false.
- 4Use the answer
A program can act on true or false directly, for example by choosing a path when the type is integral and a different path when it is not.
For int the predicate yields true; for double it yields false. Each answer is a single yes-or-no fact about the type.
Type Versus Value
A type predicate inspects the type, not the runtime value of any variable. Suppose you have a variable holding 5 and another holding 7, and both are declared as int. Asking whether int is integral gives the same answer no matter which number the variable holds, because the question is about the type int and not about the value stored in it.
The predicate for int returns the same answer whether you think of the value 5, the value 7, or any other int. The answer belongs to the type, so every value of that type shares it. This is why a type predicate is a question about categories of data rather than about the data at a given moment in the program.
Mistakes Beginners Make With Predicates
Common mistake Believing the predicate examines the current value of a variable
What it looks likeAssuming that a variable holding 5 and one holding 7 might get different answers from a type predicate about int.
Why it failsThe predicate receives a type as its subject, not a value. Its answer is a fact about the type.
Do this insteadThink of the predicate as asking a question about a category, such as int, rather than about the number currently stored.
Common mistake Writing a custom check when the standard library already provides the predicate
What it looks likeHand-coding a test for whether a type is integral instead of using the library predicate.
Why it failsType predicates are part of the standard library, so the logic is already supplied. A homemade version repeats work the library has done.
Do this insteadFind the library predicate that asks the question you need and use its answer.
Common mistake Treating the result as something other than a yes-or-no answer
What it looks likeExpecting a predicate to return a number, a description, or a list of properties.
Why it failsThe defining feature of a predicate is that it returns a true-or-false answer about the type it is given.
Do this insteadRead each predicate as a single yes-or-no question and use that answer to make the decision.
Common mistake Assuming a predicate changes how the type works
What it looks likeBelieving that asking whether a type is integral alters what the type can do.
Why it failsA type predicate is an ordinary function that reports a fact. It does not change the type or the language rules.
Do this insteadTreat the predicate as an observation: it asks a question and reports the answer without modifying anything.
Practice Reading Predicate Answers
Read each predicate expression as a yes-or-no question about its type, then state the answer. Expression A: std::is_integral<int>::value. Expression B: std::is_integral<double>::value. For each one, write the question in plain English and say whether the result is true or false.
Hints
- Translate each predicate into a sentence beginning with: is the type ... an integral type?
- int is one of the integral types, and double is not.
- A predicate answer depends only on the type inside the angle brackets.
Two variables are both declared as int, one holding 5 and the other holding 7. Explain in a few sentences why a type predicate about int gives the same answer for both, and why the answer does not depend on which number is stored.
Hints
- Ask yourself whether the predicate receives the variable or the type.
- Consider what the answer is a fact about.
Key Takeaways
- A type predicate is a standard-library type function that takes a type and returns a true-or-false answer about it.
- Predicates are ready-made library tools, so you choose the right one and interpret its answer rather than writing the check yourself.
- Read a predicate as a yes-or-no question, such as whether int is an integral type, and use that answer to decide what the program does next.
- A type predicate inspects the type, not the runtime value of any variable, so every value of the same type gets the same answer.