1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
Consider the following struct definition:
verb( struct Int
{
using type = int;
};)
Although at this point it may seem strange to embed a using declaration in a
struct, in chapter ref(ADVANCEDTEMPL) we will encounter situations where this
is actually very useful. It allows us to define a variable of a type that is
required by the template. E.g., (ignore the use of tt(typename) in the
following function parameter list, but see section ref(DISTINGUISH) for
details):
verb( template <typename Type>
void func(typename Type::type value)
{
})
When calling tt(func(10)) tt(Int) has to be specified explicitly since
there may be many structs that define tt(type): the compiler needs some
assistance. The correct call is tt(func<Int>(10)). Now that it's clear that
tt(Int) is meant, and the compiler correctly deduces that tt(value) is an
tt(int).
But templates may be overloaded and our next definition is:
verb( template <typename Type>
void func(Type value)
{})
Now, to call this function we specify tt(func<int>(10)) and
again this flawlessly compiles.
But as we've seen in the previous section when the compiler determines
which template to instantiate it creates a list of viable functions and
selects the function to instantiate by matching the parameter types of viable
functions with the provided actual argument types. To do so it has to
em(determine) the types of the parameters and herein lies a problem.
When evaluating tt(Type = int) the compiler encounters the prototypes
tt(func(int::type)) (first template definition) and tt(func(int)) (second
template definition). But there is no tt(int::type), and so in a way this
generates an error. The error results from matching the provided template type
argument with the types used in the various template definitions.
A type-problem caused by substituting a type in a template definition is,
however, em(not) considered an error, but merely an indication that that
particular type cannot be used in that particular template. The template is
therefore removed from the list of candidate functions.
This principle is known as emi(substitution failure) em(is not an error)
hi(SFINAE)(SFINAE) and it is often used by the compiler to select not only a
simple overloaded function (as shown here) but also to choose among available
template specializations (see also sections ref(CLASSORNOT) and ref(TYPECONV)).
|