So I was doing some work with a friend of mine in C++, and we came across this in the documentation.
//(until C++14)
template<class T>
struct less;
//(since C++14)
template<class T = void>
struct less;
Now I know how it works with class T = int
and the same for double and float and other types of classes. But the part I am very confused about, is how does void act in this case? And what are the limitations by using void?
I'm asking this because the C++ documentation is very helpful nor can I find anywhere else that explains it.
Given your code snippet I am going to assume you are referring the function object from the standard library, that is, std::less.
In general, the declaration template<class T = void>
works exactly as for other types (such as int
, for example).
In short, when an object of that class is instantiated without specifying the type template argument, then void
will be deducted.
std::less<int> li; // std::less<T = int>;
std::less<void> lv; // std::less<T = void>;
std::less<> lv2; // std::less<T = void>; exactly as one row above.
In this particular case, std::less
provides a template specialization when T = void
.
The object std::less<void>
is a handy specialization which allows deducing the types to compare "automatically" with the operator()
. Moreover, it needed when you want to compare two different types which are not implicitly convertible.
Practical Example:
Let us assume you have two objects you can compare.
/*Let us assume you have two objects you can compare*/
struct Foo;
struct Bar;
struct Foo {
bool operator<(const Bar&) const;
};
struct Bar {
bool operator<(const Foo&) const;
};
Foo
and Bar
can be compared to each other, but they are different types.
Which template type will you specify for the functor std::less
in this case?
void WrongCode() {
std::less<Foo> l;
l(Foo{}, Bar{}); // error
}
If we use std::less<Foo>
then the functor will only accept objects of type Foo
. (Of course, the same is for std::less<Bar>
).
Therefore, the standard provides this handy specialization to cover this case.
void GoodCode() {
std::less<> l;
l(Foo{}, Bar{}); // this compile
}
GoodCode
will compile because the types of operator()
of std::less<void>
are automatically deducted (and they can even be different).
void
is a type.
There are some restrictions on how the void
type may be used, but nevertheless, void
is a valid type in the type system. Therefore, it is allowed to have void
as an argument for a template parameter, including as a default argument.
So, if you type std::less<>
then it means std::less<void>
.
The question of what std::less<void>
means is a separate one: normally, std::less<T>
compares T
values, but there are no values of type void
. Instead, std::less<void>
is a special case: you can pass two values of any (possibly different) types to it, as long as they can be compared. See the cppreference.com article on std::less<void>
.
In general it just means that you are going to specialize a class for the type void to process a special case.
Here is a demonstrative program.
#include <iostream>
template <class T = void>
struct A
{
void operator ()( const T & t ) const
{
std::cout << "primary template\n";
std::cout << 2 * t << '\n';
}
};
template <>
struct A<>
{
template <typename U>
void operator ()( const U &u ) const
{
std::cout << "specialization for void\n";
std::cout << 10 * u << '\n';
}
};
int main()
{
A<int>()( 1 );
A<>()( 1 );
}
Its output is
primary template
2
specialization for void
10
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