How To Use void_t Alias Template in C++ 17?
In C++ 17, there is a very useful alias template for metaprogramming that can be used to simplify use of SFINAE. The void_t
is a meta-function that is used to map any types ( or types) to type void
. In this post, we explain what is void_t, how you can use it in different examples.
What is alias template void_t in C++ 17?
The void_t
is an alias template which is introduced with C++17, it is defined in
header and it is a metafunction that is used to map any types (or a sequence of any types) to type void
. The main purpose of void_t
is to make easy writing of type traits. It is used to solve SFINAE (Substitution Failure Is Not An Error) prior to concepts of C++20 standard. SFINAE rule says that If the deduced type or explicitly specified type for the template parameter fails, the specialization is discarded from the overload set instead of causing an error in compilation.
Since C++17, the std::void_t is defined as below.
template< class... > using void_t = void;
|
Now, let’s see how we can use it in template definitions.
How to use alias template void_t to check a typename in a template?
We can use void_t
to if a class has a certain typename using at compile time, here we check if it has ‘type’ typename.
template < class, class = std::void_t<> > struct hastype : std::false_type {};
template < class T > struct hastype<T, std::void_t<typename T::type>> : std::true_type {};
|
here is a full example about this, here we check ‘typeB
‘ typename if it has or not.
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 |
#include #include
struct stA { typedef int typeA; };
struct stB { typedef int typeB; }; template < class, class = std::void_t<> > struct hastype : std::false_type {};
template < class T > struct hastype<T, std::void_t<typename T::typeB>> : std::true_type {};
int main() { std::cout << “stA has typeB :” << hastype<stA>::value << std::endl; // 0 std::cout << “stB has typeB :” << hastype<stB>::value << std::endl; // 1
system(“pause”); return 0; }
|
and the output will be as follows.
stA has typename typeB :0 stB has typename typeB :1
|
How to use alias template void_t to check a member in a template?
We can use void_t
to check if there is a member in a template, i.e. we can check if it has ‘varB’ member or not, as given below.
template <class, class = std::void_t<>> struct hasmember : std::false_type {};
template <class T> struct hasmember<T, std::void_t<decltype(std::declval<T>().varB)>> : std::true_type {};
|
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 |
#include #include
struct stA { int varA; };
struct stB { int varB; };
template <class, class = std::void_t<>> struct hasmember : std::false_type {};
template <class T> struct hasmember<T, std::void_t<decltype(std::declval<T>().varB)>> : std::true_type {};
int main() { std::cout << “stA has member valB :” << hasmember<stA>::value << std::endl; // 0 std::cout << “stB has member valB :” << hasmember<stB>::value << std::endl; // 1
system(“pause”); return 0; }
|
and the output will be as follows.
stA has member valB :0 stB has member valB :1
|
How to use alias template void_t to check if a class has a function name?
We can use void_t
to check if a class has a method. Here is an example that checks if myfB()
function exists in that class.
template <class T, class = void> struct hasmethod : std::false_type {};
template <class T> struct hasmethod<T, std::void_t<decltype(std::declval<T>().myfB())>> : std::true_type {};
|
Here is a full example.
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 |
#include #include
struct stA { void myfA() { } };
struct stB { void myfB() { } };
// to check if a function is present template <class T, class = void> struct hasmethod : std::false_type {};
template <class T> struct hasmethod<T, std::void_t<decltype(std::declval<T>().myfB())>> : std::true_type {};
int main() { std::cout << “stA has method myfB :” << hasmethod<stA>::value << std::endl; // 0 std::cout << “stA has method myfB :” << hasmethod<stB>::value << std::endl; // 1
system(“pause”); return 0; }
|
and the output will be as follows.
stA has method myfB :0 stA has method myfB :1
|
How to use alias template void_t to check whether a class is iterable?
We can use void_t
to check whether a class is iterable or not. Here is a simple example.
template <typename, typename = void> constexpr bool isiterable{};
template <typename T> constexpr bool isiterable<T, std::void_t<decltype(std::declval<T>().begin()), decltype(std::declval<T>().end())>> = true;
|
Here is a full example.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include #include #include
// to check whether a class is iterable template <typename, typename = void> constexpr bool isiterable{};
template <typename T> constexpr bool isiterable<T, std::void_t<decltype(std::declval<T>().begin()), decltype(std::declval<T>().end())>> = true;
int main() { std::cout << “vector is iterable:” << isiterable<float> << std::endl; // 0 std::cout << “vector is iterable:” << isiterable<std::vector<float>> << std::endl; // 1
system(“pause”); return 0; }
|
and the output will be as follows.
vector is iterable:0 vector is iterable:1
|
As you see, interestingly the void_t
is very useful to simplify use of SFINAE for metaprogramming.
For more details about this feature in C++17 standard, please see these papers; N3911
C++ Builder is the easiest and fastest C and C++ compiler and IDE for building simple or professional applications on the Windows operating system. It is also easy for beginners to learn with its wide range of samples, tutorials, help files, and LSP support for code. RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for UIs.
There is a free C++ Builder Community Edition for students, beginners, and startups; it can be downloaded from here. For professional developers, there are Professional, Architect, or Enterprise versions of C++ Builder and there is a trial version you can download from here.