Reputation:
I have come across the following code snippet:
template <typename T, typename = void>
struct test {
int t = sizeof(T);
};
I know that in typename = void
, void is a default argument but it doesn't have a name! What is it useful for and what does it even mean?
Upvotes: 9
Views: 1080
Reputation: 433
I personally like to see it as a case of default template (type)argument to sfinae out overloads which does not meet certain criteria. First thing first, giving name to a default template argument is just fine, so the following is correct:
template <typename T, typename sometype= void>
struct test {
int t = sizeof(T);
};
In the above case , clearly the type argument sometype
is not used anywhere in the struct test. But what if instead of setting default value to void, we set it using some compile time conditions so that the template function is only valid for integral types like so ?
(borrowing code's from nathan's answer)
template <typename T>
struct test<T, typename sometype = std::enable_if_t<std::is_integral_v<T>>> {
int t = 42;
};
If the T has type integral
then sometype is defined otherwise the given template is ignored making use of sfinae.
Additionally, you can drop "sometype
" to write :
template <typename T>
struct test<T, typename = std::enable_if_t<std::is_integral_v<T>>> {
int t = 42;
};
Finally compare this with the default values used in function declarations:
void foo(int = 9); //Function declaration can have default values without names too.
void foo (int a )
{
//some code
}
Upvotes: 2
Reputation: 180500
This is used for specializations in conjunction with SFINAE. Doing this allows you to have code like
template <typename T, typename = void>
struct test {
int t = sizeof(T);
};
template <typename T>
struct test<T, std::enable_if_t<std::is_integral_v<T>>> {
// ^^ this part "fills in" the void ^^
int t = 42;
};
template <typename T>
struct test<T, std::enable_if_t<std::is_floating_point_v<T>>> {
// ^^ this part "fills in" the void ^^
int t = 21;
};
int main()
{
test<int> i;
std::cout << i.t << "\n";
test<double> d;
std::cout << d.t;
}
which outputs
42
21
Without the typename = void
, we would not be able to add these specializations because there would be no second parameter the enable_if_t
part could "fill in".
Upvotes: 14