C++ Type Aliases

Learn how to use type aliases, using statements and typedef to simplify or rename complex C++ types.
This lesson is part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

a53.jpg
Ryan McCombe
Ryan McCombe
Posted

At this point, we may have noticed our types are getting more and more verbose.

This trend is going to continue, particularly once we start using template classes.

We’ll cover template classes in more detail later in this chapter. For now, let's introduce a basic example of one from the standard library - the std::pair.

The pair data type is available by including <utility>. It lets us store two objects in a single variable. We specify the types we will be using within the < and > syntax:

#include <utility>

std::pair<int, bool> MyPair;

We can access each value through the first and second members, respectively:

#include <utility>

std::pair<int, bool> MyPair { 42, true };
MyPair.first // 42;
MyPair.second // true;

This is all we need to know about std::pair for now, but a full overview is available here:

Why we need type aliases

Let's see a more complicated example, which will show why type aliases can be useful.

We might have a consumable item in our inventory, alongside an integer quantity. We could store that as a std::pair<const ConsumableItem&, int>:

#include <utility>

class ConsumableItem {
public:
  void Consume() const {}
};

void ConsumeInventoryItem(
  std::pair<const ConsumableItem&, int> Item
) {
  if (Item.second > 0) {
	  Item.first.Consume();
	  Item.second--;
  }
}

int main() {
  ConsumableItem HealthPotion;
  int Quantity { 100 };

  std::pair<const ConsumableItem&, int> Item {
	  HealthPotion, Quantity
  };

  ConsumeInventoryItem(Item);
}

In the above code, we’re using the following type:

std::pair<const ConsumableItem&, int>

This has three problems:

  • Having to type so many characters to specify a type is annoying
  • Having it repeatedly show up in our code is making our functions hard to follow. It’s quite difficult to quickly figure out what our code is doing when so much of the signal is being drowned out by the noise of such a complex and verbose type.
  • The type has no semantic meaning, so it’s not clear what it even represents. Anyone reading our code will immediately know or can infer what types like int or Monster represent, but it takes some digging and assumptions to work out that std::pair<const ConsumableItem&, int> is supposed to be an inventory slot.

Fortunately, we have a way to give our types more friendly names.

Creating an Alias with using

We can create an alias for a type using a using statement, as shown below:

using InventorySlot =
  std::pair<const ConsumableItem&, int>;

This has at least two benefits

  • Our type is less cumbersome, meaning the code that uses it is easier to follow
  • The alias actually describes what the type is supposed to represent

Using Type Aliases

We can use the type alias in place of the type, in any location where a type would be expected. From our previous example, it has simplified our function signature and our variable creation:

#include <utility>

class ConsumableItem {
public:
  void Consume() const {
  }
};

using InventorySlot =
  std::pair<const ConsumableItem&, int>;

void ConsumeInventoryItem(InventorySlot Item) {
  if (Item.second > 0) {
	  Item.first.Consume();
	  Item.second--;
  }
}

int main() {
  ConsumableItem HealthPotion;
  int Quantity { 100 };

  InventorySlot Item { HealthPotion, Quantity };

  ConsumeInventoryItem(Item);
}

Through the alias, we can freely add qualifiers to the underlying type. This can include things like * or & to make it a pointer or a reference type, and const to make it a constant:

ConsumableItem HealthPotion;
InventorySlot Potions { HealthPotion, 100 };
Potions.second++;

// Pointer to an inventory slot
InventorySlot* Pointer { &Potions };
Pointer->second++;

// A constant inventory slot
const InventorySlot ConstantSlot { Potions };
ConstantSlot.second++;  // not allowed

Alias Scope

Aliases are scoped in the same way as any of our other declarations.

This means aliases can have global scope, by being defined outside of any block:

using InventorySlot = std::pair<Item*, int>;

int main() {
  InventorySlot Slot { &CheeseWheel, 100 }
}

Alternatively, aliases can be defined within a block, such as one created by a function, namespace (including an anonymous namespace) or an if statement.

When this is done, the alias will only be available within that block, including any nested child blocks.

In the following example, line 7 will now throw an error, as the alias is only available within the block created as part of MyFunction

void MyFunction() {
  using InventorySlot = std::pair<Item, int>;
  InventorySlot Slot { BreadRoll, 50 }
}

int main() {
  InventorySlot Slot { CheeseWheel, 100 }
}

decltype

Occasionally, it will be easier (or necessary) to ask the compiler to figure out what type an expression returns. We can do this using the decltype function.

This returns the type of the expression, which we can use anywhere in our code where a type would be expected.

Here are some examples:

#include <utility>

int main(){
  std::pair<int, int> SomePair;

  decltype(SomePair) AnotherPair;

  using PairType = decltype(SomePair);
  PairType AThirdPair;
}

typedef

C++ also offers another way to accomplish type aliasing - typedef.

The concept is very similar, although with typedef, the type comes first, followed by the alias:

typedef std::pair<const Item&, int> InventorySlot;

The support of typedef is mostly for historic reasons, but it still crops up a lot in existing code so it's worth knowing about.

New code should use the using approach, as described previously.

Was this lesson useful?

Ryan McCombe
Ryan McCombe
Posted
This lesson is part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Templates
7a.jpg
This lesson is part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access!

This course includes:

  • 106 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Next Lesson

Variable Templates

An introduction to C++ templates, why we need them, and how to create variable templates.
18.jpg
Contact|Privacy Policy|Terms of Use
Copyright © 2023 - All Rights Reserved