Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CPlusPlusNotesForProfessionals.pdf
Скачиваний:
47
Добавлен:
20.05.2023
Размер:
5.11 Mб
Скачать

Chapter 93: Type Traits

Section 93.1: Type Properties

Version ≥ C++11

Type properties compare the modifiers that can be placed upon di erent variables. The usefulness of these type traits is not always obvious.

Note: The example below would only o er an improvement on a non-optimizing compiler. It is a simple a proof of concept, rather than complex example.

e.g. Fast divide by four.

template<typename T>

inline T FastDivideByFour(cont T &var) {

// Will give an error if the inputted type is not an unsigned integral type. static_assert(std::is_unsigned<T>::value && std::is_integral<T>::value,

"This function is only designed for unsigned integral types."); return (var >> 2);

}

Is Constant:

This will evaluate as true when type is constant.

std::cout << std::is_const<const int>::value << "\n"; // Prints true. std::cout << std::is_const<int>::value << "\n"; // Prints false.

Is Volatile:

This will evaluate as true when the type is volatile.

std::cout << std::is_volatile<static volatile int>::value << "\n"; // Prints true. std::cout << std::is_const<const int>::value << "\n"; // Prints false.

Is signed:

This will evaluate as true for all signed types.

std::cout << std::is_signed<int>::value << "\n"; // Prints true. std::cout << std::is_signed<float>::value << "\n"; // Prints true.

std::cout << std::is_signed<unsigned int>::value << "\n"; // Prints false. std::cout << std::is_signed<uint8_t>::value << "\n"; // Prints false.

Is Unsigned:

Will evaluate as true for all unsigned types.

std::cout << std::is_unsigned<unsigned int>::value << "\n"; // Prints true. std::cout << std::is_signed<uint8_t>::value << "\n"; // Prints true. std::cout << std::is_unsigned<int>::value << "\n"; // Prints false. std::cout << std::is_signed<float>::value << "\n"; // Prints false.

GoalKicker.com – C++ Notes for Professionals

490

Section 93.2: Standard type traits

Version ≥ C++11

The type_traits header contains a set of template classes and helpers to transform and check properties of types at compile-time.

These traits are typically used in templates to check for user errors, support generic programming, and allow for optimizations.

Most type traits are used to check if a type fulfils some criteria. These have the following form:

template <class T> struct is_foo;

If the template class is instantiated with a type which fulfils some criteria foo, then is_foo<T> inherits from std::integral_constant<bool,true> (a.k.a. std::true_type), otherwise it inherits from std::integral_constant<bool,false> (a.k.a. std::false_type). This gives the trait the following members:

Constants

static constexpr bool value

true if T fulfils the criteria foo, false otherwise

Functions

operator bool

Returns value

Version ≥ C++14

bool operator()

Returns value

Types

 

 

 

 

 

Name

 

 

Definition

 

value_type

 

bool

 

 

 

 

 

 

 

 

 

type

 

std::integral_constant<bool,value>

The trait can then be used in constructs such as static_assert or std::enable_if. An example with std::is_pointer:

template <typename T>

void i_require_a_pointer (T t) { static_assert(std::is_pointer<T>::value, "T must be a pointer type");

}

//Overload for when T is not a pointer type template <typename T>

typename std::enable_if<!std::is_pointer<T>::value>::type does_something_special_with_pointer (T t) {

//Do something boring

}

//Overload for when T is a pointer type template <typename T>

GoalKicker.com – C++ Notes for Professionals

491

typename std::enable_if<std::is_pointer<T>::value>::type does_something_special_with_pointer (T t) {

//Do something special

}

There are also various traits which transform types, such as std::add_pointer and std::underlying_type. These traits generally expose a single type member type which contains the transformed type. For example, std::add_pointer<int>::type is int*.

Section 93.3: Type relations with std::is_same<T, T>

Version ≥ C++11

The std::is_same<T, T> type relation is used to compare two types. It will evaluate as boolean, true if the types are the same and false if otherwise.

e.g.

// Prints true on most x86 and x86_64 compilers. std::cout << std::is_same<int, int32_t>::value << "\n"; // Prints false on all compilers.

std::cout << std::is_same<float, int>::value << "\n"; // Prints false on all compilers.

std::cout << std::is_same<unsigned int, int>::value << "\n";

The std::is_same type relation will also work regardless of typedefs. This is actually demonstrated in the first example when comparing int == int32_t however this is not entirely clear.

e.g.

// Prints true on all compilers. typedef int MyType

std::cout << std::is_same<int, MyType>::value << "\n";

Using std::is_same to warn when improperly using a templated class or function.

When combined with a static assert the std::is_same template can be valuable tool in enforcing proper usage of templated classes and functions.

e.g. A function that only allows input from an int and a choice of two structs.

#include <type_traits> struct foo {

int member;

// Other variables

};

struct bar { char member;

};

template<typename T>

int AddStructMember(T var1, int var2) {

// If type T != foo || T != bar then show error message. static_assert(std::is_same<T, foo>::value ||

std::is_same<T, bar>::value,

"This function does not support the specified type.");

GoalKicker.com – C++ Notes for Professionals

492

return var1.member + var2;

}

Section 93.4: Fundamental type traits

Version ≥ C++11

There are a number of di erent type traits that compare more general types.

Is Integral:

Evaluates as true for all integer types int, char, long, unsigned int etc.

std::cout << std::is_integral<int>::value << "\n"; // Prints true. std::cout << std::is_integral<char>::value << "\n"; // Prints true. std::cout << std::is_integral<float>::value << "\n"; // Prints false.

Is Floating Point:

Evaluates as true for all floating point types. float,double, long double etc.

std::cout << std::is_floating_point<float>::value << "\n"; // Prints true. std::cout << std::is_floating_point<double>::value << "\n"; // Prints true. std::cout << std::is_floating_point<char>::value << "\n"; // Prints false.

Is Enum:

Evaluates as true for all enumerated types, including enum class.

enum fruit {apple, pair, banana};

enum class vegetable {carrot, spinach, leek};

std::cout << std::is_enum<fruit>::value << "\n"; // Prints true. std::cout << std::is_enum<vegetable>::value << "\n"; // Prints true. std::cout << std::is_enum<int>::value << "\n"; // Prints false.

Is Pointer:

Evaluates as true for all pointers.

std::cout << std::is_pointer<int *>::value << "\n"; // Prints true. typedef int* MyPTR;

std::cout << std::is_pointer<MyPTR>::value << "\n"; // Prints true. std::cout << std::is_pointer<int>::value << "\n"; // Prints false.

Is Class:

Evaluates as true for all classes and struct, with the exception of enum class.

struct FOO {int x, y;}; class BAR {

public: int x, y;

};

enum class fruit {apple, pair, banana};

std::cout << std::is_class<FOO>::value << "\n"; // Prints true. std::cout << std::is_class<BAR>::value << "\n"; // Prints true. std::cout << std::is_class<fruit>::value << "\n"; // Prints false.

GoalKicker.com – C++ Notes for Professionals

493

std::cout << std::is_class<int>::value << "\n"; // Prints false.

GoalKicker.com – C++ Notes for Professionals

494