BogoToBogo
  • Home
  • About
  • Big Data
  • Machine Learning
  • AngularJS
  • Python
  • C++
  • go
  • DevOps
  • Kubernetes
  • Algorithms
  • More...
    • Qt 5
    • Linux
    • FFmpeg
    • Matlab
    • Django 1.8
    • Ruby On Rails
    • HTML5 & CSS

C++ Tutorial - Traits : A Template Specialization - 2020

cplusplus_icon.png




Bookmark and Share





bogotobogo.com site search:




Traits - A Template Specialization

The traits is a big topic which may require pages of tutorials. Here in this tutorial, however, we'll just get the brief introduction to traits.


Suppose we want to get max values for int or double, we do this:

#include <iostream>
#include <climits>
using namespace std;

int main()
{
	cout << "max values\n";
	cout << "int: " << INT_MAX << endl;
	cout << "double: " << DBL_MAX << endl;

	return 0;
}

And get the following output:

max values
int: 2147483647
double: 1.79769e+308

Then, how about float or unsigned int?

If we do not remember the name for float, we have to look it up from somewhere to get the max value.

How about this?

#include <iostream>
// #include <climits>
#include <limits>
using namespace std;

int main()
{
	cout << "max values\n";
	cout << "int: " << numeric_limits<int>::max() << endl;
	cout << "double: " << numeric_limits<double>::max() << endl;
	cout << "float: " << numeric_limits<float>::max() << endl;
	cout << "unsigned int: " << numeric_limits<unsigned int>::max() << endl;

	return 0;
}

Output:

max values
int: 2147483647
double: 1.79769e+308
float: 3.40282e+038
unsigned int: 4294967295

We don't have to remember the name for our query, only the compiler needs to know the type.

In the code, we used the header <limits> instead of <climits>, and the query was, numeric_limits<type>::max().

What happened?

The numeric_limits template class replaced/supplemented the ordinary preprocessor constants of C (<climits> or <limits.h>).




numeric_limits traits class

Actually, in the limits.h, for example, DBL_MAX contains the "maximum value" trait for the double data type. However, by using a traits class such as numeric_limits, the type becomes part of the name, so that the maximum value for a double becomes numeric_limits<double>::max(), and also, we don't need to know the type.

Usually, we use templates to implement something once for any type. But we can also use templates to provide a common interface that is implemented for each type. We do this by providing specialization of a general template.

In this tutorial, we'll see the numeric_limits is the typical example of specialization:

Here is a general template that provides the default numeric values for any type:

namespace std
{
	/* general numeric limits as default for any type */
	template <typename T>
	class numeric_limits
	{
	public:
		// no specialization for numeric limit exists
		static const bool is_specialized = false;
		...
	};
}

The general template of the numeric limits shown above is telling that there are no numeric limits available for type T by setting the member is_specialized to false.

We can write a specialized version of the template as below:

namespace std
{
	/* setting numeric limits for int type */
	template <>
	class numeric_limits<int>
	{
	public:
		// Now we have a specialization for numeric limit for int.
		// It does exists.
		static const bool is_specialized = true;
		static int min() throw() {
			return -2147483648;
		}
		static int max() throw() {
			return 2147483647;
		}
		static const int digits = 31;
		...
	};
}

The general numeric_limits template and its standard specialization are provided in the header file <limits>. The specialization are provided for any fundamental type that can represent numeric values: bool, char, signed char, unsigned char, wchar_t, short, unsigned short, int, unsigned int, long, unsigned long, float, double, and long double. They can be supplemented easily for user-defined numeric types.

#include <iostream>
#include <limits>
using namespace std;

int main()
{
	cout << "is_signed(char): " 
		<< numeric_limits<char>::is_signed << endl;
	cout << "is_specialized(long double): "
		<< numeric_limits<long double>::is_specialized << endl;
	cout << "is_specialized(std::string): "
		<< numeric_limits<std::string>::is_specialized << endl;

	return 0;
}

If we run the code, the std::string gives false for is_specialized as expected:

is_signed(char): 1
is_specialized(long double): 1
is_specialized(std::string): 0



What is Traits?

So, what is traits?

Traits gives us additional information other than just the type. More exactly, we can get some information about a type.

That's what traits let you do: they allow you to get information about a type during compilation. ...

The fact that traits must work with built-in types means that things like nesting information inside types won't do, because there's no way to nest information inside pointers. The traits information for a type, then must be external to the type. The standard technique is to put it into a template and cone or more specializations of that template.

...

By convention, traits are always implemented as structs. Another convention is that the structs used to implement traits are knows as trait classes.

-Scott Meyers #Item 47: "Use traits classes for information about types" of his book Effective C++ 55 Specific Ways to Improve Your Programs and Designs.



Traits of std::iterator, please visit Templates.

For template specialization, please visit Template Specialization.







Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization

YouTubeMy YouTube channel

Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong






Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong






C++ Tutorials

C++ Home

Algorithms & Data Structures in C++ ...

Application (UI) - using Windows Forms (Visual Studio 2013/2012)

auto_ptr

Binary Tree Example Code

Blackjack with Qt

Boost - shared_ptr, weak_ptr, mpl, lambda, etc.

Boost.Asio (Socket Programming - Asynchronous TCP/IP)...

Classes and Structs

Constructor

C++11(C++0x): rvalue references, move constructor, and lambda, etc.

C++ API Testing

C++ Keywords - const, volatile, etc.

Debugging Crash & Memory Leak

Design Patterns in C++ ...

Dynamic Cast Operator

Eclipse CDT / JNI (Java Native Interface) / MinGW

Embedded Systems Programming I - Introduction

Embedded Systems Programming II - gcc ARM Toolchain and Simple Code on Ubuntu and Fedora

Embedded Systems Programming III - Eclipse CDT Plugin for gcc ARM Toolchain

Exceptions

Friend Functions and Friend Classes

fstream: input & output

Function Overloading

Functors (Function Objects) I - Introduction

Functors (Function Objects) II - Converting function to functor

Functors (Function Objects) - General



Git and GitHub Express...

GTest (Google Unit Test) with Visual Studio 2012

Inheritance & Virtual Inheritance (multiple inheritance)

Libraries - Static, Shared (Dynamic)

Linked List Basics

Linked List Examples

make & CMake

make (gnu)

Memory Allocation

Multi-Threaded Programming - Terminology - Semaphore, Mutex, Priority Inversion etc.

Multi-Threaded Programming II - Native Thread for Win32 (A)

Multi-Threaded Programming II - Native Thread for Win32 (B)

Multi-Threaded Programming II - Native Thread for Win32 (C)

Multi-Threaded Programming II - C++ Thread for Win32

Multi-Threaded Programming III - C/C++ Class Thread for Pthreads

MultiThreading/Parallel Programming - IPC

Multi-Threaded Programming with C++11 Part A (start, join(), detach(), and ownership)

Multi-Threaded Programming with C++11 Part B (Sharing Data - mutex, and race conditions, and deadlock)

Multithread Debugging

Object Returning

Object Slicing and Virtual Table

OpenCV with C++

Operator Overloading I

Operator Overloading II - self assignment

Pass by Value vs. Pass by Reference

Pointers

Pointers II - void pointers & arrays

Pointers III - pointer to function & multi-dimensional arrays

Preprocessor - Macro

Private Inheritance

Python & C++ with SIP

(Pseudo)-random numbers in C++

References for Built-in Types

Socket - Server & Client

Socket - Server & Client 2

Socket - Server & Client 3

Socket - Server & Client with Qt (Asynchronous / Multithreading / ThreadPool etc.)

Stack Unwinding

Standard Template Library (STL) I - Vector & List

Standard Template Library (STL) II - Maps

Standard Template Library (STL) II - unordered_map

Standard Template Library (STL) II - Sets

Standard Template Library (STL) III - Iterators

Standard Template Library (STL) IV - Algorithms

Standard Template Library (STL) V - Function Objects

Static Variables and Static Class Members

String

String II - sstream etc.

Taste of Assembly

Templates

Template Specialization

Template Specialization - Traits

Template Implementation & Compiler (.h or .cpp?)

The this Pointer

Type Cast Operators

Upcasting and Downcasting

Virtual Destructor & boost::shared_ptr

Virtual Functions



Programming Questions and Solutions ↓

Strings and Arrays

Linked List

Recursion

Bit Manipulation

Small Programs (string, memory functions etc.)

Math & Probability

Multithreading

140 Questions by Google



Qt 5 EXPRESS...

Win32 DLL ...

Articles On C++

What's new in C++11...

C++11 Threads EXPRESS...

Go Tutorial

OpenCV...








Contact

BogoToBogo
contactus@bogotobogo.com

Follow Bogotobogo

About Us

contactus@bogotobogo.com

YouTubeMy YouTube channel
Pacific Ave, San Francisco, CA 94115

Pacific Ave, San Francisco, CA 94115

Copyright © 2024, bogotobogo
Design: Web Master