C++17 new feature - constructor automatically deduce the type of template

Introduction

Many classes in C++ need to specify a type. In fact, this type can be derived from the constructor called by the user. However, prior to C++17, this was an unstandardized feature. C++17 allows the compiler to automatically deduce the template type from the called constructor.
Use the simplest method to create std::pair and std::tuple instances. It can be created in one step.

std::pair my_pair (123, "abc"); // std::pair<int, const char*>
std::tuple my_tuple (123, 12.3, "abc"); // std::tuple<int, double, const char*>

Workflow

Let's define a class to see the value of automated template type inference.

template <typename T1, typename T2, typename T3> class my_wrapper {
T1 t1; T2 t2; T3 t3;
public:
explicit my_wrapper(T1 t1_, T2 t2_, T3 t3_)
: t1{t1_}, t2{t2_}, t3{t3_}
{}
/* ... */
};

good! We define a template class. Before C++17, in order to create an instance of this class:

my_wrapper<int, double, const char *> wrapper {123, 1.23, "abc"};

We omit the template specialization part:

my_wrapper wrapper {123, 1.23, "abc"};

Before C++17, we might implement a factory function in the following way:

my_wrapper<T1, T2, T3> make_wrapper(T1 t1, T2 t2, T3 t3)
{
return {t1, t2, t3};
}

Use factory function:

auto wrapper (make_wrapper(123, 1.23, "abc"));

Note: There are many factory functions in STL, such as std::make_shared, std::make_unique,
std::make_tuple, etc. In C++17, these factory functions are obsolete. Of course, considering compatibility, these factory functions will be retained in the future.

syntax extension

We've already looked at implicit template type deduction. But in some cases, type inference cannot be relied upon. Such as the following example:

// example class template <typename T> struct sum{
T value;

template <typename ... Ts>
sum(Ts&& ... values) : value{(values + ...)} {}
};

In the structure, sum can accept any number of arguments and add them together using a folding expression (later in this chapter, we will discuss folding expressions to understand more about folding expressions). details). The result of the addition operation is stored in the value variable. Now the question is, what is the type of T? If we don't specify it explicitly, we need to deduce it from the variable type passed to the constructor. When we provide multiple string instances, their type is std::string. When we provide multiple integer types, their type is int. When we provide multiple integers, floats, and double floats
, the compiler determines which type is suitable for all values ​​without losing information. To implement the above derivation, we provide guided explicit derivation:

template <typename ... Ts>
sum(Ts&& ... ts) -> sum<std::common_type_t<Ts...>>;

Guided deduction tells the compiler to use the feature of std::common_type_t, which finds a common type for all values. Let’s see how to use it:

sum s {1u, 2.0, 3, 4.0f};
sum string_sum {std::string{"abc"}, "def"}; std::cout << s.value << '\n'
<< string_sum.value << '\n';

In line 1, we create a sum object, and the parameter types of the constructor are unsigned, double, int and float.
std::common_type_t will return double as the common type, so what we get is a sun instance. In line 2, we create a std::string instance and a C-style string. Under our guidance, the compiler deduces that the type of this instance is sumstd::string.
When we run this code, 10 and abcdef will be printed on the screen. Among them, 10 is the value of numeric sum, and abcdef is the value of string sum.

Guess you like

Origin blog.csdn.net/EBDSoftware/article/details/128483019