what template <class = typename T::type>
means? Can you refer me to some blog, specification describing this?
The question originaly came from explanation of sfinae on cpp reference
template <typename A>
struct B { typedef typename A::type type; };
template <
class T,
class = typename T::type, // SFINAE failure if T has no member type
class U = typename B<T>::type // hard error if T has no member type
// (guaranteed to not occur as of C++14)
> void foo (int);
First, I'll explain typename T::type
. This is simply the access of a member type. Here's an example of accessing a member type:
struct foo {
using bar = int;
};
int main() {
foo::bar var{};
// var has type int
}
So why the typename
? It simply means we want to access a type. Since we are in a template and T
is an unknown type, and foo::bar
could also mean accessing a static variable. To disambiguate, we denote that we effectively want to access a type by explicitly typing typename
.
Okay, now what does the class =
means?
The class =
means the same thing as typename =
. When declaring template type parameters, we introduce then using class
or typename
:
template<typename A, typename B>
struct baz {};
But as any parameters in C++, the name is optional. I could have wrote this and the following is completely equivalent:
template<typename, typename>
struct baz {};
Also, you know in function parameters, we can specify default values? Like that:
void func(int a, int b = 42);
int main () {
func(10); // parameter b value is 42
// We are using default value
}
We can also omit parameter names:
void func(int, int = 42);
Just like function parameters, template parameters can have it's name omitted, and can have a default value.
template<typename, typename = float>
struct baz {};
baz<int> b; // second parameter is float
Now we have this declaration:
template <
class T,
class = typename T::type, // SFINAE failure if T has no member type
class U = typename B<T>::type // hard error if T has no member type
// (guaranteed to not occur as of C++14)
> void foo (int);
Here we declare a function that takes an int as parameter, and has three template parameter.
The fist parameter is a simple named parameter. The name is T
and it's a type template parameter. The second is also a type parameters, but it has no name. However, it has a default value of T::type
, which is a member type of T
. We are explicitly telling the compiler that T::type
must be a member type of T
by specifying typename
. The third parameter is similar to the second.
This is where SFINAE kicks in: when a default parameter is used, but T::type
as as a member type don't exist, how can you assign the second template parameter to that? We can't. If T::type
don't exists, we cannot assign the second template parameter. But instead of making it an error, the compiler will simply try another function, because there is a chance another function would be callable.
This is quite similar to simple overloading. You have the f
function. It takes a float
parameter, an another overload that takes a std::string
. Imagine you call f(9.4f)
. Does the compiler choke because a std::string
is not constructible from a float
? No! The compiler ain't stupid. It will try another overload, and will find the float
version and call it. In SFINAE a similar analogy can be made. The compiler won't stop because there's some overload somewhere that needs an undefined type in a template parameter. It will try another overload.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With