Type aliases interact with const
and volatile
qualifiers in interesting ways. Understanding these interactions is crucial for writing correct and maintainable C++ code. Let's explore this topic with some examples.
When you create a type alias, you can add const
and volatile
qualifiers to it, or to the underlying type:
#include <iostream>
using Integer = int;
using ConstInteger = const int;
int main() {
Integer i{42};
ConstInteger ci{10};
// OK
i = 100;
// Error: assignment of read-only variable ci
ci = 20;
// This is equivalent to 'const int ci2{30};
const Integer ci2{30};
// Error: assignment of read-only variable ci2
ci2 = 40;
}
error: 'ci': you cannot assign to a variable that is const
error: 'ci2': you cannot assign to a variable that is const
Things get more interesting with pointers and references:
using IntPtr = int*;
using ConstIntPtr = const int*;
using IntConstPtr = int* const;
int main() {
int value{42};
IntPtr p1{&value};
ConstIntPtr p2{&value};
IntConstPtr p3{&value};
*p1 = 10; // OK
// Error: assignment of read-only location
*p2 = 20;
*p3 = 30; // OK
int anotherValue{100};
p1 = &anotherValue; // OK
p2 = &anotherValue; // OK
// Error: assignment of read-only variable 'p3'
p3 = &anotherValue;
}
error: 'p2': you cannot assign to a variable that is const
error: 'p3': you cannot assign to a variable that is const
In this example:
IntPtr
is a pointer to int
ConstIntPtr
is a pointer to const int
(can't modify the pointed-to value)IntConstPtr
is a const
pointer to int
(can't change what it points to)You can add qualifiers to type aliases:
using Integer = int;
int main() {
// Equivalent to const int ci{42};
const Integer ci{42};
// Equivalent to volatile int vi{10};
volatile Integer vi{10};
// Error: assignment of read-only variable 'ci'
ci = 100;
// OK, but compiler won't optimize access to 'vi'
vi = 20;
}
error: 'ci': you cannot assign to a variable that is const
Type aliases can be particularly useful with templates:
#include <iostream>
#include <vector>
template <typename T>
using ConstRef = const T&;
int main() {
std::vector<int> vec{1, 2, 3};
ConstRef<std::vector<int>> constVecRef = vec;
// Error: 'constVecRef' is read-only
constVecRef.push_back(4);
for (ConstRef<int> element : constVecRef) {
std::cout << element << ' ';
}
}
error: 'push_back()': cannot convert from 'const std::vector<int>' to 'std::vector<int>'
note: Conversion loses qualifiers
In this example, ConstRef<T>
is an alias template for a const reference to T
.
Understanding these interactions allows you to write more expressive and type-safe code. Remember, type aliases don't create new types - they're just new names for existing types. This means that the const
and volatile
qualifiers behave exactly as they would with the original types.
Answers to questions are automatically generated and may not have been reviewed.
Learn how to use type aliases, using
statements, and typedef
to simplify or rename complex C++ types.