**Associated Types**
The implementation of

perimeter() works with the triangle class, but it is suboptimal; despite the fact that the sides of the triangle are specified in terms of integers, all of the computation in

perimeter() is performed via floating-point arithmetic. To solve this problem, the algorithm should instead perform the computation using the same type that the polygon uses to express the lengths of its sides, which may vary from one type to another.

Concepts provide a way to express such types, which vary from one use of a concept to another: *associated types*. Associated types are declared within the body of a concept via the typename keyword (using the same syntax as template type parameters), and can be used to describe operations within the concept. You can now revise the Polygon concept to introduce an associated type named length_type, which is used to express the length of a single side in the polygon, and therefore is the return type of the side_length() operation:

```
concept Polygon<typename P> {
typename length_type
int num_sides(const P&);
length_type side_length(const P&, int index);
}
```

Because the types of concept operations are important wherever the concepts are used, you can refer to an associated type as a nested type within the concept. For example, an updated

perimeter() algorithm should refer to the

length_type of the

Polygon concept explicitly, rather than using double:

```
template<typename P>
requires Polygon<P>
Polygon<P>::length_type perimeter(const P& poly) {
Polygon<P>::length_type sum = 0; // error!
for (int i = 0; i < num_sides(poly); ++i)
sum += side_length(poly, i); // error!
return sum; // error!
}
```

Here, the uses of double are replaced with

Polygon<P>::length_type, which has made the algorithm capable of handling different length types, and therefore more reusable. However, this change has introduced some new errors that will be detected by the compiler. Previously, the algorithm was relying on the built-in operations provided by double: construction from an integer, addition via

+=, and copy-construction of the return value. With an arbitrary

length_type, you can no longer assume that all of these operations are available. They have to be specified as requirements on the length type, which the user's length type must satisfy.

**Member-Function Requirements**

To express the length type's requirements, we introduce another new concept, Numeric. The Numeric concept provides the essential operations required to sum a value:

```
auto concept Numeric<typename T> {
T::T(const T&); // copy construction
T::T(int); // construction from an int
T::~T(); // destructor
T& operator+=(T&, const T&); // addition
}
```

The first three operations in the

Numeric concept require a copy constructor (which can be satisfied by a built-in initialization), the ability to construct a value of type

T from an int, and the ability to destroy an object of type

T. Each of these operations is stated using member function syntax with the

T:: prefix, specifying that these operations apply to objects of type

T. The same syntax can be used to describe specific member functions requirements (for example,

T::clone()).

Armed with the Numeric concept, you can express the perimeter() algorithm's full requirements as:

```
template<typename P>
requires Polygon<P> && Numeric<Polygon<P>::length_type>
Polygon<P>::length_type perimeter(const P& poly);
```

The

"&&" in the

requires clause states that both requirements must be satisfied for the algorithm to be usable, that is, the type

P must be a

Polygon and its

length_type must be

Numeric. Any number of different requirements can be added to a template using

"&&", including multiple requirements on the same types.